Skip to content

feat: add task remove-metrics-session and stop the auditor contradicting itself - #224

Merged
bborbe merged 6 commits into
masterfrom
feat/remove-metrics-session
Sep 27, 2026
Merged

bborbe merged 6 commits into
masterfrom
feat/remove-metrics-session

Conversation

@bborbe

@bborbe bborbe commented Sep 27, 2026

Copy link
Copy Markdown
Owner

Implements spec 055 (specs/in-progress/055-remove-metrics-session.md), generated and executed through the dark-factory pipeline as prompts 235–237.

What this ships

1. vault-cli task remove-metrics-session <task-name> <session-id> — removes every metrics_sessions entry carrying that session id, preserving every other entry and every other frontmatter key. It is the counterpart of append-metrics-session and the only path that clears one entry by id.

  • The key is deleted when the last entry goes, not left as an empty list.
  • A call matching nothing exits non-zero and writes nothing — the file is byte-identical. A silent no-op is the exact defect this verb exists to close.
  • The session id is validated as a well-formed UUID before the task is read, so a caller-supplied string can never reach the YAML block.
  • It takes no clock and never writes claude_session_id.

2. task-auditor no longer recommends a goal link its own alignment check would then score as a MAJOR orphan. One guard sentence in § Task-Goal Alignment, between the orphan bullet and the implementation-level bullet, so the advice and the check share one predicate. On 2026-09-15 that contradiction cost two extra audit cycles plus an operator ruling on a single task.

Why the obvious fix does not work

Adding metrics_sessions to the knownTaskListFields allowlist is inert, for three mechanical reasons — each verified against the tree:

  • metricsSessionsWriteRefusal runs at pkg/ops/frontmatter_entity.go:743, before the allowlist check at :750, so the refusal still fires and the entry changes nothing.
  • The dispatch switch at :760-768 reads only Goals() / Tags() / BlockedBy() — all []string — so a map-valued field falls through setting nothing.
  • The allowlist is shared by add and remove, so the entry would also open task add metrics_sessions ….

The refusal introduced in v0.147.0 stays absolute: metricsSessionsWriteRefusal and knownTaskListFields are byte-identical to their previous state, and the existing AC4 refusal spec is unmodified.

Supersession

Spec 053's non-goal says "Do NOT add a clear path for the field — removing entries stays an operator frontmatter action." The shared-session rule that shipped the same evening requires clearing any entry carrying a shared id, so that ruling is reversed here. Spec 053 now carries a forward pointer to this one rather than a stale prohibition.

Verification

  • make test — passes clean, all packages.
  • integration/cli_test.go gains a Describe("task remove-metrics-session") block covering the two-entry removal, key deletion on the last entry, duplicate-id removal, the absent-id failure, the malformed-id refusal, and an assertion that the generic verbs still refuse the field.
  • The new command is registered in the command-registration table (docs/dod.md requires it).
  • mocks/remove-metrics-session-operation.go is generated, not hand-written; the generator's header-stripping of mocks/mocks.go was not carried.

Pipeline note

Authored as three dark-factory prompts, each audited by prompt-auditor before approval. Those audits caught six Critical defects across the spec and the prompts — including a prompt that instructed reuse of fixture helpers that are closure-local (a compile failure as written) and one whose own worked example failed the grep it set as its own gate.

Starting the dark-factory daemon to generate spec 055's prompts also re-triggered
generation for spec 041, which is approved but whose generation keeps failing
("generation produced no prompt files"). The daemon rewrote all three of 041's
prompt files with new created timestamps and edited prose.

Those files belong to another spec, are not part of spec 055, and were not
reviewed here — so this commit restores them to their state on origin/master.
Reverting is the conservative choice: it returns the repo to where it stood
before this run touched anything outside its scope.

Spec 041's own regeneration failure is recorded on the driving task and is not
fixed here.
The daemon flipped the spec to verifying when the last of its three prompts landed.
Bookkeeping for this spec, carried onto the branch so the PR records the state.
master moved to cc314a0 (PR #222, the sibling goal-link-framing change) while this
branch was in review. That PR touches the same two files, so both conflicted.

agents/task-auditor.md auto-merged: the sibling's clause sits after the theme
carve-out (line 249), this branch's guard sentence between the orphan bullet and
the implementation-level bullet (line 244), so neither displaces the other.

CHANGELOG.md was resolved by hand and the fold guard caught a real error in the
first attempt: the sibling's bullet had already been RELEASED as v0.149.1 on
master, and the initial resolution folded it back under ## Unreleased — silently
un-releasing it. Corrected: this branch's two bullets stay under ## Unreleased,
and master's ## v0.149.1 section is restored with its bullet in place. Verified
with the fold guard (prints only '+## Unreleased') and by asserting each bullet's
owning section with awk.

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chunk 1/5

Now I have a complete picture of all the changed files. Let me compile the review:

Review Complete

Summary

The PR implements two distinct changes:

  1. New task remove-metrics-session verb — removes every metrics_sessions entry carrying a given session ID from a task, with proper UUID validation before file read, preservation of other entries, key deletion when the last entry goes, and loud failure when the ID matches nothing.

  2. task-auditor fix — the Task-Goal Alignment check no longer recommends a goal link that its own orphan-scoring would then reject.

The implementation is correct, well-tested, and the behavioral invariants are well-documented.


Must Fix (Critical)
None.

Should Fix (Important)
None.

Nice to Have (Optional)
None.

Notes:

  • The removeMetricsSession in pkg/ops/metrics_session_remove.go:63 correctly uses the domain RemoveMetricsSession which atomically handles all edge cases (no match, last entry, duplicate IDs).
  • UUID validation before task read is correct per spec — invalid IDs are refused with nothing read or written.
  • The concurrent-append race is explicitly documented as accepted in docs/work-on-session-lifecycle.md:101-104.
  • The task-auditor.md fix at lines 243-244 is a one-line guard sentence addition that prevents the contradiction.
{
  "verdict": "approve",
  "summary": "PR adds a well-designed `task remove-metrics-session` verb (spec 055) with complete unit and integration test coverage, and fixes the task-auditor's goal-link recommendation to no longer contradict its own orphan-scoring. UUID validation before file read, key deletion on last entry, and loud failure on no-match are all correctly implemented.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "not-an-issue",
      "detail": "RemoveMetricsSession in domain deletes the key when last entry goes (line 72-73), returns 0 and leaves field untouched on no-match (line 69-71), removes all duplicate-ID entries in one pass (line 63-68). ops layer validates UUID before reading task (metrics_session_remove.go:55-58) and never calls WriteTask when id matches nothing (line 64-69)."
    },
    {
      "concern": "correctness: CLI integration for new remove-metrics-session task",
      "disposition": "not-an-issue",
      "detail": "createTaskRemoveMetricsSessionCommand registered in createTaskCommands (cli.go:1345), dispatches through FirstSuccess vault dispatcher (cli.go:2481-2487), operation created with taskStorage (cli.go:2484-2485)."
    },
    {
      "concern": "correctness: auditor contradiction fix - ensure guard sentence is consistent",
      "disposition": "not-an-issue",
      "detail": "Line 244 of task-auditor.md now recommends theme-only linkage explicitly when the goal can be marked complete without the task, preventing the prior contradiction where a recommended goal link would be scored as orphan."
    }
  ]
}

Chunk 2/5

Based on my review of all the changed files in this chunk, I have enough information to provide a comprehensive assessment. Let me compile the findings.


PR Review: feat: add task remove-metrics-session and stop the auditor contradicting itself

Selector Mode Traceability

Candidates: Rules matched by Step 4b-i glob filter
Applicable: Rules selected by Step 4c-sel
Skipped: Rules classified as non-applicable


Must Fix (Critical)

None.

Should Fix (Important)

None.

Nice to Have (Optional)

None.

Plan Concerns

{
  "concerns": [
    {"area": "correctness", "file": "pkg/ops/metrics_session_remove.go", "note": "new operation for removing metrics sessions - verify cleanup is complete"},
    {"area": "correctness", "file": "pkg/cli/cli.go", "note": "CLI integration for new remove-metrics-session task"},
    {"area": "correctness", "file": "agents/task-auditor.md", "note": "auditor contradiction fix - ensure guard sentence is consistent"}
  ]
}

Adjudication of Mechanical Findings

The mechanical funnel flagged RemoveMetricsSession (task_frontmatter_metrics.go:58-78) for two context-related rules:

  1. go-context/cancel-check-in-loop (SHOULD): The for-loop over sessions should check ctx.Done() each iteration.

  2. go-functional-composition/list-checks-ctx-done (MUST): The method iterates without checking ctx.Done() between iterations.

Adjudication: These findings do not apply. RemoveMetricsSession is a pure in-memory domain method — it accepts no context.Context parameter. The method operates on a local []MetricsSession slice via kept = append(kept, entry), which is bounded by the slice length. Cancellation semantics (ctx.Done()) apply to blocking I/O operations, not to iterating over a local in-memory slice. The ast-grep rule cannot distinguish between a loop over external data (where cancellation matters) and a loop over a local slice (where it does not). The flag is a false positive.

The go-architecture-assistant findings about f.MetricsSessions(), f.Delete(...), and f.Set(...) being "package-level function calls" are also false positives — these are receiver methods on TaskFrontmatter, not calls to external package functions. The rule misidentified f. receiver methods as package-level function calls.

Manual Review of Chunk 2 Files

File Assessment
pkg/domain/task_frontmatter_metrics.go RemoveMetricsSession is correct: iterates with a simple for range, preserves order of survivors, deletes the key when the last entry is removed, returns the count of removed entries, and is a no-op when nothing matches. Well-documented with precise behavior guarantees.
pkg/domain/task_frontmatter_metrics_test.go 6 comprehensive test cases covering: removal + survivor preservation, duplicate-id removal, key deletion when last entry removed, no-match returns 0 and leaves field untouched, absent key returns 0. All cases match the method's documented contract.
pkg/ops/metrics_session_remove.go Correct design: UUID validation happens before reading the task (correct ordering — fails fast on bad input without I/O), delegates removal to the domain layer, returns error when nothing matched (preserving file byte-for-byte), wraps find and write errors. No issues.
pkg/ops/metrics_session_remove_test.go 6 Ginkgo test cases covering: survivor write, no-match skip-write, UUID validation edge cases (empty, non-UUID, path separator), find failure wrapping, write failure propagation. Comprehensive.
mocks/remove-metrics-session-operation.go Counterfeiter-generated mock. Signature matches RemoveMetricsSessionOperation.Execute(context.Context, string, string, string) error. Correct.
pkg/cli/cli.go createTaskRemoveMetricsSessionCommand correctly uses dispatcher.FirstSuccess, passes taskName and sessionID in the correct order to removeOp.Execute, handles JSON/plain output formatting, and has the nolint:dupl,gocognit,nestif directive justified by the intentional structural similarity to createTaskAppendMetricsSessionCommand.

Notes:

  • The nolint:dupl on createTaskRemoveMetricsSessionCommand is legitimate — it suppresses duplicate code warnings for a command that is structurally parallel to createTaskAppendMetricsSessionCommand (same pattern: entity command with a session id argument, dispatcher.FirstSuccess, operation creation, error handling, JSON/plain formatting). The duplicate is intentional, not accidental.
  • The RemoveMetricsSession domain method is intentionally silent on cancellation — it is an in-memory slice filter, not an I/O operation. This is correct by design.

{
  "verdict": "approve",
  "summary": "Clean feature implementation: the remove-metrics-session verb is correctly wired from CLI through to the domain layer, with UUID pre-validation before I/O, no-op preservation when nothing matches, and comprehensive test coverage. The mechanical ctx.Done() findings are false positives — the domain method has no context parameter and operates on a local in-memory slice.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: pkg/ops/metrics_session_remove.go - new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "addressed",
      "detail": "UUID validation is done BEFORE reading the task (line 55-58), removal delegates to domain.TaskFrontmatter.RemoveMetricsSession which filters the slice and writes survivors, write is only called when something was actually removed (line 70), error wrapping for find and write failures is correct."
    },
    {
      "concern": "correctness: pkg/cli/cli.go - CLI integration for new remove-metrics-session task",
      "disposition": "addressed",
      "detail": "Command is registered in createTaskCommands (line 1345), uses dispatcher.FirstSuccess for multi-vault, passes taskName and sessionID in correct order, handles JSON/plain output formatting, nolint:dupl is justified by intentional structural similarity to createTaskAppendMetricsSessionCommand."
    },
    {
      "concern": "correctness: agents/task-auditor.md - auditor contradiction fix - ensure guard sentence is consistent",
      "disposition": "not-an-issue",
      "detail": "This file is in chunk 1, not chunk 2. The concern is outside the scope of this review chunk."
    }
  ]
}

Chunk 3/5

I've completed my review. Let me now produce the final report.

Step 4 summary:

The ast-grep runner was unavailable in this environment (toolchain gap), so Step 4a could not run. I evaluated the mechanical findings from the pre-computed funnel against the actual files.

Mechanical funnel findings — all verified as non-issues:

Rule Finding Verification
go-architecture/counterfeiter-directive-on-interface Interface at line 20 flagged //counterfeiter:generate directive is present above the interface (line 20)
go-testing/counterfeiter-mocks-required Interface at line 20 flagged mocks/remove-metrics-session-operation.go exists and is counterfeiter-generated
go-composition/no-package-function-calls-in-business-logic (×6) Direct calls to uuid.Validate, errors.Wrapf, errors.Wrap, errors.Errorf, task.RemoveMetricsSession All six calls are via the injected taskStorage field or standard domain methods — consistent with every other operation in pkg/ops/ (e.g., baseline.go, show.go, escalation.go)
go-testing/no-bare-error-call (×4) FindTaskByNameReturns(...) and WriteTaskReturns(nil) in BeforeEach flagged These are mock configuration calls, not calls that return error values — their return signature is () (void); errcheck only flags calls with an un-discarded error return

Step 4b-i candidate rules: All candidates are either not applicable to these new files or classified as skipped (no violations confirmed in the real files).

Selector mode: clean — no adjudication needed


{
  "verdict": "approve",
  "summary": "Chunk 3/5 review of pkg/ops/metrics_session_remove.go and pkg/ops/metrics_session_remove_test.go. All mechanical funnel findings are confirmed false positives: the interface carries the required counterfeiter directive, the mock file exists, errors package calls follow established codebase conventions, and mock setup calls in BeforeEach are void-returning configuration calls not subject to errcheck. No real violations remain.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "not-an-issue",
      "detail": "metrics_session_remove.go:55-73 - Execute validates UUID first, then calls task.RemoveMetricsSession (domain/RemoveMetricsSession) which filters entries and deletes the key when the list empties. WriteTask is only called when removed > 0, so a no-match call writes nothing. Counterfeiter directive present at line 20, mock generated at mocks/remove-metrics-session-operation.go. Design is sound."
    },
    {
      "concern": "correctness: test coverage for remove-metrics-session operation",
      "disposition": "not-an-issue",
      "detail": "metrics_session_remove_test.go covers: match-and-remove (survivor preserved), no-match (no write), UUID validation for empty/invalid/path-separator inputs, wrapped find failure, and wrapped write failure. ops_suite_test.go exists in pkg/ops/ so Ginkgo will discover these specs."
    }
  ]
}

Chunk 4/5

Based on my thorough review of this PR, I have no findings to report. The implementation is correct.

{
  "verdict": "approve",
  "summary": "PR adds the `task remove-metrics-session` verb end-to-end (domain method, ops operation, CLI command, mock, and tests) plus a guard sentence in the task auditor. The implementation is correct: UUID validation before read, structural no-write guarantee when nothing matches, key deletion when last entry goes, correct error wrapping, proper JSON/plain output contract, and the frozen refusal files are untouched.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "not-an-issue",
      "detail": "RemoveMetricsSession filters by SessionID, preserves order, deletes key when last entry goes, and returns 0 (no modification) when nothing matches. The ops layer only calls WriteTask when removed > 0, giving a structural no-write guarantee for the AC4 case."
    },
    {
      "concern": "correctness: CLI integration for new remove-metrics-session task",
      "disposition": "not-an-issue",
      "detail": "createTaskRemoveMetricsSessionCommand registered at cli.go:1345, factory at line 2462, uses FirstSuccess dispatcher for multi-vault, JSON mode returns PrintJSON result (exit 0) while plain mode propagates error (exit non-zero) per established contract."
    },
    {
      "concern": "correctness: auditor contradiction fix - ensure guard sentence is consistent",
      "disposition": "not-an-issue",
      "detail": "Guard sentence at agents/task-auditor.md:244 reads 'never recommend linking a goal the alignment check will then score as an orphan' — positioned between the orphan bullet (line 243) and the implementation-level bullet (line 244), and git diff shows exactly one added line."
    }
  ]
}

Chunk 5/5

Selector guide unavailable (blocked by sandbox path restriction). Continuing with mechanical findings and manual review.

Mechanical findings: 0 (ast-grep funnel clean).

Step 7 — Manual Review of changed files:

The diff covers:

  1. pkg/ops/metrics_session_remove.go — new operation
  2. pkg/domain/task_frontmatter_metrics.go — RemoveMetricsSession domain method
  3. pkg/cli/cli.go — createTaskRemoveMetricsSessionCommand wiring
  4. pkg/ops/metrics_session_remove_test.go — unit tests
  5. pkg/domain/task_frontmatter_metrics_test.go — domain method tests
  6. integration/cli_test.go — 7 AC integration tests
  7. agents/task-auditor.md — one-sentence guard fix
  8. docs/work-on-session-lifecycle.md — session lifecycle documentation
  9. CHANGELOG.md — feature entries

Findings:

  • pkg/ops/metrics_session_remove.go — Implementation is clean. UUID validation before read. Zero-write on no-match (by returning error without calling WriteTask). Uses domain RemoveMetricsSession (not a string-level frontmatter rewrite). No stamp, no clock, no claude_session_id touch. Correct.

  • pkg/domain/task_frontmatter_metrics.go — RemoveMetricsSession correctly deletes the key when the last entry goes (line 73: f.Delete("metrics_sessions")). Returns 0 on nil/absent/non-list input. Preserves order of survivors.

  • pkg/cli/cli.go — createTaskRemoveMetricsSessionCommand (line 2462) properly uses dispatcher.FirstSuccess, takes exactly 2 args, passes them correctly, and handles JSON/plain output formatting. Registered at line 1345.

  • Integration tests — 7 ACs covering: single removal, last-entry-deletes-key, duplicate-id removal, no-match fails loudly + writes nothing, invalid UUID refuses before read, generic verbs still refuse metrics_sessions, JSON output contract. All correct.

  • agents/task-auditor.md — Single-line addition: "When the goal can be marked complete without this task, never recommend linking a goal the alignment check will then score as an orphan — recommend theme-only linkage instead and say so explicitly." This is precisely the fix for the contradiction noted in the PR title.

  • CHANGELOG.md — Two clear entries under ## Unreleased matching the PR scope. Version strings unchanged (v0.149.0 is the latest tagged, Unreleased is unreleased).

{
  "verdict": "approve",
  "summary": "Clean implementation of RemoveMetricsSessionOperation and the task-auditor contradiction fix. All operations are well-structured, tested across unit/domain/integration layers, and the documentation explains the design rationale thoroughly.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: new operation for removing metrics sessions",
      "disposition": "not-an-issue",
      "detail": "RemoveMetricsSessionOperation validates UUID before read, returns error on no-match without writing, uses domain method (not string-level rewrite), and WriteTask is called only on successful removal. pkg/ops/metrics_session_remove.go lines 55-73."
    },
    {
      "concern": "correctness: CLI integration for remove-metrics-session task",
      "disposition": "not-an-issue",
      "detail": "createTaskRemoveMetricsSessionCommand at pkg/cli/cli.go:2462-2509 wires the operation correctly via FirstSuccess dispatcher, takes exactly 2 args, formats JSON/plain output correctly, and is registered at line 1345."
    },
    {
      "concern": "correctness: auditor contradiction fix",
      "disposition": "not-an-issue",
      "detail": "agents/task-auditor.md line 244 adds the guard sentence preventing the auditor from recommending a goal link its own alignment check would then orphan. The fix is a single correct sentence."
    }
  ]
}
{"verdict":"approve","reason":"chunked review: all 5 chunks approved","concerns_addressed":[{
      "concern": "correctness: new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "not-an-issue",
      "detail": "RemoveMetricsSession in domain deletes the key when last entry goes (line 72-73), returns 0 and leaves field untouched on no-match (line 69-71), removes all duplicate-ID entries in one pass (line 63-68). ops layer validates UUID before reading task (metrics_session_remove.go:55-58) and never calls WriteTask when id matches nothing (line 64-69)."
    },{
      "concern": "correctness: CLI integration for new remove-metrics-session task",
      "disposition": "not-an-issue",
      "detail": "createTaskRemoveMetricsSessionCommand registered in createTaskCommands (cli.go:1345), dispatches through FirstSuccess vault dispatcher (cli.go:2481-2487), operation created with taskStorage (cli.go:2484-2485)."
    },{
      "concern": "correctness: auditor contradiction fix - ensure guard sentence is consistent",
      "disposition": "not-an-issue",
      "detail": "Line 244 of task-auditor.md now recommends theme-only linkage explicitly when the goal can be marked complete without the task, preventing the prior contradiction where a recommended goal link would be scored as orphan."
    },{
      "concern": "correctness: pkg/ops/metrics_session_remove.go - new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "addressed",
      "detail": "UUID validation is done BEFORE reading the task (line 55-58), removal delegates to domain.TaskFrontmatter.RemoveMetricsSession which filters the slice and writes survivors, write is only called when something was actually removed (line 70), error wrapping for find and write failures is correct."
    },{
      "concern": "correctness: pkg/cli/cli.go - CLI integration for new remove-metrics-session task",
      "disposition": "addressed",
      "detail": "Command is registered in createTaskCommands (line 1345), uses dispatcher.FirstSuccess for multi-vault, passes taskName and sessionID in correct order, handles JSON/plain output formatting, nolint:dupl is justified by intentional structural similarity to createTaskAppendMetricsSessionCommand."
    },{
      "concern": "correctness: agents/task-auditor.md - auditor contradiction fix - ensure guard sentence is consistent",
      "disposition": "not-an-issue",
      "detail": "This file is in chunk 1, not chunk 2. The concern is outside the scope of this review chunk."
    },{
      "concern": "correctness: new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "not-an-issue",
      "detail": "metrics_session_remove.go:55-73 - Execute validates UUID first, then calls task.RemoveMetricsSession (domain/RemoveMetricsSession) which filters entries and deletes the key when the list empties. WriteTask is only called when removed > 0, so a no-match call writes nothing. Counterfeiter directive present at line 20, mock generated at mocks/remove-metrics-session-operation.go. Design is sound."
    },{
      "concern": "correctness: test coverage for remove-metrics-session operation",
      "disposition": "not-an-issue",
      "detail": "metrics_session_remove_test.go covers: match-and-remove (survivor preserved), no-match (no write), UUID validation for empty/invalid/path-separator inputs, wrapped find failure, and wrapped write failure. ops_suite_test.go exists in pkg/ops/ so Ginkgo will discover these specs."
    },{
      "concern": "correctness: new operation for removing metrics sessions - verify cleanup is complete",
      "disposition": "not-an-issue",
      "detail": "RemoveMetricsSession filters by SessionID, preserves order, deletes key when last entry goes, and returns 0 (no modification) when nothing matches. The ops layer only calls WriteTask when removed > 0, giving a structural no-write guarantee for the AC4 case."
    },{
      "concern": "correctness: CLI integration for new remove-metrics-session task",
      "disposition": "not-an-issue",
      "detail": "createTaskRemoveMetricsSessionCommand registered at cli.go:1345, factory at line 2462, uses FirstSuccess dispatcher for multi-vault, JSON mode returns PrintJSON result (exit 0) while plain mode propagates error (exit non-zero) per established contract."
    },{
      "concern": "correctness: auditor contradiction fix - ensure guard sentence is consistent",
      "disposition": "not-an-issue",
      "detail": "Guard sentence at agents/task-auditor.md:244 reads 'never recommend linking a goal the alignment check will then score as an orphan' — positioned between the orphan bullet (line 243) and the implementation-level bullet (line 244), and git diff shows exactly one added line."
    },{
      "concern": "correctness: new operation for removing metrics sessions",
      "disposition": "not-an-issue",
      "detail": "RemoveMetricsSessionOperation validates UUID before read, returns error on no-match without writing, uses domain method (not string-level rewrite), and WriteTask is called only on successful removal. pkg/ops/metrics_session_remove.go lines 55-73."
    },{
      "concern": "correctness: CLI integration for remove-metrics-session task",
      "disposition": "not-an-issue",
      "detail": "createTaskRemoveMetricsSessionCommand at pkg/cli/cli.go:2462-2509 wires the operation correctly via FirstSuccess dispatcher, takes exactly 2 args, formats JSON/plain output correctly, and is registered at line 1345."
    },{
      "concern": "correctness: auditor contradiction fix",
      "disposition": "not-an-issue",
      "detail": "agents/task-auditor.md line 244 adds the guard sentence preventing the auditor from recommending a goal link its own alignment check would then orphan. The fix is a single correct sentence."
    }]}

@ben-s-pull-request-reviewer
ben-s-pull-request-reviewer Bot dismissed their stale review September 27, 2026 10:39

superseded by new automated review

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chunk 1/5

I now have enough information for a thorough review. Let me consolidate findings.


PR Review: feat: add task remove-metrics-session and stop the auditor contradicting itself

Scope: 14 files changed, 1142 insertions, 1 deletion — across Go implementation (pkg/ops/, pkg/cli/, pkg/domain/), tests, mocks, integration tests, agent definition, docs, and changelog.

Step 3: make precommit skipped (selector mode) — CI covers lint+test.

Step 4: ast-grep unavailable — mechanical funnel skipped. Manual review of all changed Go files against applicable rules.

Selector mode traceability:

  • Candidates: All judgment rules in rules/index.json with glob-matching triggers
  • Skipped: All rules whose trigger glob does not match any of the 14 changed files — includes all go-k8s-*, go-http-service/*, go-cqrs/*, go-k8s-crd/*, go-build-args/*, go-http-handler/*, go-library/*, go-factory/* (no pkg/factory/ touched), go-licensing/* (LICENSE present), etc.
  • Applicable:
    • go-errors/no-bare-return-err — Go files in pkg/ops/, pkg/cli/, pkg/domain/
    • go-errors/no-context-background-in-business-logic — same
    • go-errors/no-fmt-errorf — same
    • go-doc/exported-item-must-have-comment — all new exported types/functions in new files
    • go-architecture/counterfeiter-directive-on-interface — new interface RemoveMetricsSessionOperation
    • go-architecture/new-prefix-constructor-naming — NewRemoveMetricsSessionOperation
    • changelog/conventional-prefix-required — CHANGELOG.md
    • changelog/unreleased-entry-required — CHANGELOG.md
    • go-licensing/source-file-header-required — all new .go files
    • go-test-quality-assistant concerns — test files
    • go-context-assistant concerns — context propagation in ops

Step 7 (Manual Review):

pkg/ops/metrics_session_remove.go — New operation. Error wrapping uses github.com/bborbe/errors (errors.Wrapf/errors.Errorf) throughout, no fmt.Errorf, no bare return err. Context propagated on all calls. UUID validation runs before task read (AC5 guarantee). WriteTask is never called when removed == 0 — the file stays byte-identical by construction. Doc comment explains every design decision. Interface+constructor+private struct pattern correct. //counterfeiter:generate directive present. ✅

pkg/cli/cli.go (createTaskRemoveMetricsSessionCommand, lines 2461–2509) — New CLI command. Uses PrintJSON for structured output (no raw encoding/json), correct cobra.ExactArgs(2) args check, vault dispatcher pattern identical to sibling mutation commands. //nolint:dupl,gocognit,nestif suppresses linter warnings about structural similarity — intentional per the comment. JSON error branch returns PrintJSON's result (normally nil → exit 0 with success:false), plain branch propagates error → exit non-zero. This asymmetry is the established contract per the append verb and AC7 integration test. ✅

pkg/domain/task_frontmatter_metrics.go — RemoveMetricsSession method: filters by SessionID == sessionID, returns 0 and leaves field untouched on no match (removed == 0 early return, no Set call), deletes key on last survivor (Delete), otherwise Set with survivors. Duplicate IDs removed fully (not once). Correct. ✅

pkg/domain/task_frontmatter_metrics_test.go (lines 296–369) — Describe("RemoveMetricsSession",...) with 5 specs covering: removes named entry + preserves survivor's own id AND started_at; removes all entries with duplicated id; deletes key on last entry (asserts key absent, not merely empty); returns 0 and leaves field untouched on no match; returns 0 on absent key and on non-list value. All semantics asserted. ✅

pkg/ops/metrics_session_remove_test.go — 6 specs covering: matching id writes survivors once; no-match exits non-zero with "nothing removed" message AND WriteTaskCallCount() == 0; invalid UUID / empty / path-bearing id each refused BEFORE task read (FindTaskByNameCallCount() == 0); find failure wrapped; write failure wrapped. All ACs pinned. Uses context.Background() in BeforeEach — test setup exempt per rule. ✅

mocks/remove-metrics-session-operation.go — Counterfeiter-generated mock for RemoveMetricsSessionOperation. Execute method matches interface signature. var _ ops.RemoveMetricsSessionOperation = new(RemoveMetricsSessionOperation) compile-time interface check present. ✅

integration/cli_test.go (lines 2874–3151) — 7 AC integration specs (AC1–AC7) plus --help smoke test. Uses SHA-256 file comparison for byte-identicality checks (AC4, AC5, AC6). Entry-line prefix matching (- session_id: <id>) avoids false positives from task_identifier fields. countMetricsEntries counts block-sequence items correctly. AC7 JSON output contract checked for both success and non-success paths. Registration table entry added. ✅

agents/task-auditor.md (line 244) — One guard sentence added as sub-bullet of item 3, between the orphan flag and implementation-level bullets. Contains exact substring never recommend linking a goal the alignment check will then score as an orphan. Threshold unchanged; guards advice only. ✅

CHANGELOG.md — ## Unreleased section added above ## v0.149.1. Two bullets: feat: for the removal verb (specific, names command, field, per-entry semantics, key deletion, loud failure, UUID validation), fix: for the auditor (describes the self-contradiction fix and the fallback recommendation). Conventional prefixes correct. ✅

docs/work-on-session-lifecycle.md — New section added describing the removal verb's shape, why generic verbs cannot do it (entry is a map, set stores scalar, add/remove comma-split scalars), key deletion on last entry, loud failure on no-match, and why ClearMetricsSessions is not the tool (shared-session rule reads from all metrics_sessions ids). ✅

specs/in-progress/055-remove-metrics-session.md — Status updated from draft → verifying, with timestamps for approval/generating/prompted/verifying. ✅

Notes: No blocking issues found. The PR correctly avoids touching pkg/ops/metrics_session_write.go (the refusal) and pkg/ops/frontmatter_entity.go (knownTaskListFields). The //nolint:dupl on the CLI command is intentional and acknowledged. The context.Background() in ops test BeforeEach is the established test-setup convention. precommit skipped (selector mode) — CI runs lint+test as the authoritative gate.

{
  "verdict": "approve",
  "summary": "Clean PR adding the `task remove-metrics-session` verb end-to-end (domain method, ops operation, CLI command, counterfeiter mock, unit and integration tests, docs, changelog) and fixing the task-auditor self-contradiction. All semantics are correctly implemented: UUID validation before task read, no write on no-match, key deletion on last entry, duplicate IDs removed fully, refusal untouched. No `fmt.Errorf`, no bare `return err`, all errors wrapped with `github.com/bborbe/errors`, context propagated throughout.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: auditor \"contradicting itself\" fix — verify logic consistency in guard conditions",
      "disposition": "not-an-issue",
      "detail": "agents/task-auditor.md:244 — guard sentence added as sub-bullet between orphan flag and implementation-level bullets. Contains exact verbatim substring. Guards advice only; threshold unchanged."
    },
    {
      "concern": "correctness: new operation — check error handling, context propagation, and resource cleanup",
      "disposition": "not-an-issue",
      "detail": "pkg/ops/metrics_session_remove.go — uses errors.Wrapf/Wrap/Errorf, context propagated on all calls, WriteTask called only when removed > 0, uuid.Validate before task read."
    },
    {
      "concern": "correctness: new CLI command wiring — verify command registration and flag handling",
      "disposition": "not-an-issue",
      "detail": "pkg/cli/cli.go:2461-2509 — cobra.ExactArgs(2), vault dispatcher, PrintJSON for JSON output, nolint:dupl acknowledged, asymmetry in JSON vs plain error paths matches established contract."
    },
    {
      "concern": "tests: new test coverage — verify edge cases and error paths are covered",
      "disposition": "not-an-issue",
      "detail": "pkg/ops/metrics_session_remove_test.go has 6 specs; pkg/domain/task_frontmatter_metrics_test.go has 5 specs; integration/cli_test.go has 7 AC specs. All ACs pinned with explicit assertions including WriteTaskCallCount==0 on no-match and FindTaskByNameCallCount==0 on invalid UUID."
    },
    {
      "concern": "correctness: metrics domain logic — check metric label/key consistency",
      "disposition": "not-an-issue",
      "detail": "pkg/domain/task_frontmatter_metrics.go:58-77 — RemoveMetricsSession filters by SessionID, returns 0 on no match without Set, deletes key on last entry, Set with survivors otherwise. Duplicate IDs removed in full."
    }
  ]
}

Chunk 2/5

Based on my thorough review of the chunk 2/5 files, here is my report:

Review Summary

Chunk 2/5 files reviewed: mocks/remove-metrics-session-operation.go, pkg/cli/cli.go, pkg/domain/task_frontmatter_metrics.go, pkg/domain/task_frontmatter_metrics_test.go

Mechanical funnel findings (Step 4a): All 5 findings are false positives — the ast-grep relation layer cannot distinguish receiver methods from package-level calls, and cannot see that RemoveMetricsSession takes no context.Context parameter.

Selector-mode classification:

  • Candidates: 0 rules from Step 4b-i (could not read rules/index.json from working directory)
  • All mechanical findings adjudicated as false positives

No Must Fix, Should Fix, or Nice to Have issues found. The implementation is correct:

  • RemoveMetricsSession removes all entries matching a session ID, deletes the key when last entry is removed, and returns 0 when nothing matches
  • The RemoveMetricsSessionOperation validates UUID before reading, fails loudly when nothing matches, and correctly delegates to domain
  • The CLI wires everything properly with error wrapping and JSON/text output modes
  • Tests cover: single removal, multi-removal, last-entry deletion, no-match, absent key, wrong type, UUID validation edge cases
{
  "verdict": "approve",
  "summary": "Chunk 2/5: New remove-metrics-session verb correctly implemented with proper domain logic, UUID validation, error handling, and comprehensive test coverage. All 5 ast-grep mechanical findings are false positives — ast-grep misidentified receiver methods as package-level calls and flagged a loop for ctx.Done() checks on a function that has no context parameter.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: go-composition/no-package-function-calls-in-business-logic (3 findings on task_frontmatter_metrics.go:58,72,75)",
      "disposition": "not-an-issue",
      "detail": "FALSE POSITIVE — ast-grep cannot distinguish receiver methods (f.MetricsSessions(), f.Delete(), f.Set()) from package-level function calls. These are all method calls on *TaskFrontmatter, not pkg.Function(...) calls. Rule incorrectly matched."
    },
    {
      "concern": "correctness: go-context/cancel-check-in-loop and go-functional-composition/list-checks-ctx-done (2 findings on task_frontmatter_metrics.go:57,61)",
      "disposition": "not-an-issue",
      "detail": "FALSE POSITIVE — RemoveMetricsSession(sessionID string) has no context.Context parameter. There is no ctx to check in the loop. The rule applied to a function signature where context does not exist."
    },
    {
      "concern": "correctness: RemoveMetricsSession domain logic",
      "disposition": "addressed",
      "detail": "RemoveMetricsSession correctly: (1) calls MetricsSessions() to read current entries, (2) filters by SessionID, (3) returns 0 without writes when nothing removed, (4) calls Delete when last entry is removed, (5) calls Set with survivors otherwise. Implementation matches spec 055."
    },
    {
      "concern": "correctness: RemoveMetricsSessionOperation validation and error handling",
      "disposition": "addressed",
      "detail": "uuid.Validate called before FindTaskByName (fail-fast), returns error when nothing matches (0 removed), correctly delegates to domain TaskFrontmatter.RemoveMetricsSession. No WriteTask when nothing removed (byte-identical by construction)."
    },
    {
      "concern": "correctness: CLI command wiring",
      "disposition": "addressed",
      "detail": "createTaskRemoveMetricsSessionCommand properly registered, uses VaultDispatcher.FirstSuccess for multi-vault, handles JSON/text output, wraps errors with context."
    },
    {
      "concern": "tests: RemoveMetricsSession test coverage",
      "disposition": "addressed",
      "detail": "5 test cases covering: single removal preserves survivor, multi-removal (duplicate id), last-entry deletion (key removed), no-match returns 0 unchanged, absent key returns 0, non-list value returns 0. All domain-level edge cases covered."
    }
  ]
}

Chunk 3/5

Now I have a complete picture of both files. Let me compile the findings:

pkg/ops/metrics_session_remove.go

  • Counterfeiter directive is present (line 20) — the ast-grep funnel reports it as missing because the directive sits on the line directly above the interface; the pattern can't see the comment block above. The generated mocks/remove-metrics-session-operation.go confirms it was applied.
  • The uuid.Validate, errors.Wrapf, errors.Errorf, errors.Wrap calls are package-level utility calls. Per the rule, each capability should be wrapped in an interface — but these are pure validation/error-building utilities with no observable state. The struct correctly injects only taskStorage (the actual I/O dependency). This is a judgment-level concern, not a correctness defect.
  • task.RemoveMetricsSession(sessionID) at line 62 is a domain method on the already-injected *domain.Task — not a package-level call violation.

pkg/ops/metrics_session_remove_test.go

  • Suite file pkg/ops/ops_suite_test.go exists — the ast-grep finding is a false positive; the test is discoverable.
  • FindTaskByNameReturns and WriteTaskReturns calls at lines 36, 44, 116, 130 are Counterfeiter-generated mock methods with zero return values (func(...) not func(...) error). They are side-effect setup calls in BeforeEach/It blocks — the rule's own exemption applies.

The implementation is correct and well-tested.

{
  "verdict": "approve",
  "summary": "RemoveMetricsSessionOperation is correctly implemented: directive present, mock generated, suite file exists, all error paths tested, no-write-on-no-match correctness verified, and session ID validated before any I/O.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: missing counterfeiter directive on RemoveMetricsSessionOperation interface",
      "disposition": "addressed",
      "detail": "Directive is present at metrics_session_remove.go:20. ast-grep reported it as missing because it looks at the interface line rather than the comment block above it. The generated mocks/remove-metrics-session-operation.go confirms go generate ran successfully."
    },
    {
      "concern": "correctness: no-bare-error-call in test file (FindTaskByNameReturns/WriteTaskReturns discarding return values)",
      "disposition": "addressed",
      "detail": "These are Counterfeiter-generated mock methods with zero return values (func(...), not func(...) error). The rule's own exemption applies: 'calls that genuinely return nothing'. Suite file pkg/ops/ops_suite_test.go exists so specs are discoverable."
    },
    {
      "concern": "correctness: package-level function calls (uuid.Validate, errors.*) in Execute",
      "disposition": "not-an-issue",
      "detail": "uuid.Validate and errors package functions are pure utilities with no observable state variation. The struct correctly injects taskStorage (the sole I/O dependency). This is a judgment-level rule; the code is correct as-is."
    },
    {
      "concern": "tests: edge cases and error paths in RemoveMetricsSessionOperation",
      "disposition": "addressed",
      "detail": "All error paths covered: invalid UUID (empty, non-UUID, path-separator), find failure, write failure, no-match failure. Also covered: survivors written correctly, write not called when nothing matches."
    }
  ]
}

Chunk 4/5

{
  "verdict": "approve",
  "summary": "The PR adds a `task remove-metrics-session` verb (domain method, ops operation, CLI command, mock, and tests) plus a guard sentence in task-auditor preventing self-contradicting goal-link recommendations. All code is correct: the operation validates UUID before reading, writes only when something changed (structural guarantee via domain), and correctly propagates context. The guard sentence is properly positioned between the orphan-check and implementation-level bullets. The mechanical funnel ran clean (79 rules, 0 findings).",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: auditor \"contradicting itself\" fix — verify logic consistency in guard conditions",
      "disposition": "addressed",
      "detail": "task-auditor.md line 244: guard sentence is strictly between 'Flag orphans as MAJOR' (line 243) and 'Flag implementation-level tasks' (line 245). Text: 'never recommend linking a goal the alignment check will then score as an orphan — recommend theme-only linkage instead and say so explicitly.' Exactly matches the spec AC 8 grep string."
    },
    {
      "concern": "correctness: new operation — check error handling, context propagation, and resource cleanup",
      "disposition": "addressed",
      "detail": "metrics_session_remove.go: uuid.Validate runs before any read (AC5 structural guarantee); FindTaskByName wraps errors with 'find task'; WriteTask wraps with 'write task'; removed==0 returns error without calling WriteTask (byte-identical guarantee is structural). Context is propagated on all error paths. No resource leaks."
    },
    {
      "concern": "correctness: new CLI command wiring — verify command registration and flag handling",
      "disposition": "addressed",
      "detail": "cli.go line 1345: command registered as AddCommand alongside append-metrics-session. Uses FirstSuccess dispatcher pattern matching other task mutations. JSON branch returns PrintJSON result (normally nil) before plain branch propagates error — exactly matching the append's established contract. No encoding/json import; no new flags."
    },
    {
      "concern": "tests: new test coverage — verify edge cases and error paths are covered",
      "disposition": "addressed",
      "detail": "Domain specs (task_frontmatter_metrics_test.go:296-369): removes named entry preserving survivor id+started_at, removes all entries with duplicated id, deletes key when last entry goes, returns 0 when nothing matches, returns 0 on absent/non-list key. Ops specs (metrics_session_remove_test.go): matching id writes once with survivors, non-matching id returns error with id in message and WriteTaskCallCount==0, empty/not-uuid/../escape each return error without calling FindTaskByName, find/write failures are wrapped."
    },
    {
      "concern": "correctness: metrics domain logic — check metric label/key consistency",
      "disposition": "addressed",
      "detail": "RemoveMetricsSession correctly filters MetricsSessions() on SessionID equality, calls Delete('metrics_sessions') when last entry removed, Set with kept survivors otherwise, returns removed count. coerceMetricsSession skips entries with empty session_id (lenient degradation). All field names consistent with existing append/clear paths."
    }
  ]
}

Chunk 5/5

I've completed my review of all changed files. Let me compile the findings.

Review Summary

Mechanical funnel: Pre-computed, 0 findings.

Manual review covered:

  • pkg/ops/metrics_session_remove.go — new operation
  • pkg/ops/metrics_session_remove_test.go — unit tests
  • pkg/domain/task_frontmatter_metrics.go — domain logic
  • pkg/cli/cli.go — CLI command wiring
  • agents/task-auditor.md — auditor fix (1-line addition)
  • docs/work-on-session-lifecycle.md — lifecycle docs
  • integration/cli_test.go — integration tests
  • CHANGELOG.md — release notes

Selector mode guide: Not available in this environment (mechanical funnel results used instead).


Must Fix (Critical): None.

Should Fix (Important): None — all code is correct.

Nice to Have (Optional): None.

Notes:

  • pkg/ops/metrics_session_remove.go:55-57 validates UUID before reading the task — correct early-reject pattern.
  • The "no-match = no write" property (line 64-68) is verified by metrics_session_remove_test.go AC4 using SHA-256 comparison — correct.
  • RemoveMetricsSession domain method correctly deletes the key when the last entry is removed (task_frontmatter_metrics.go:72-74).
  • The task-auditor.md one-line fix (line 244) correctly prevents the self-contradicting recommendation by adding a guard clause.
  • docs/work-on-session-lifecycle.md is a durable design doc covering the full session lifecycle including the new removal verb.
  • Integration tests (AC1–AC7) cover: exact removal, last-entry key deletion, duplicate-id removal, no-match failure, UUID validation, generic-verb refusal, and JSON output contract.
  • CHANGELOG is well-formed with both binary and agent/plugin changes.
{
  "verdict": "approve",
  "summary": "PR adds a well-designed `remove-metrics-session` verb with thorough unit and integration test coverage, a correct domain-layer implementation that deletes the key when the last entry is removed, proper UUID validation before any read, and a one-line fix to the task-auditor that prevents a self-contradicting goal-link recommendation.",
  "comments": [],
  "concerns_addressed": [
    {
      "concern": "correctness: auditor \"contradicting itself\" fix — verify logic consistency in guard conditions",
      "disposition": "addressed",
      "detail": "agents/task-auditor.md line 244: guard clause added at Task-Goal Alignment step 3 — 'When the goal can be marked complete without this task, never recommend linking a goal the alignment check will then score as an orphan — recommend theme-only linkage instead and say so explicitly.'"
    },
    {
      "concern": "correctness: new operation — check error handling, context propagation, and resource cleanup",
      "disposition": "addressed",
      "detail": "pkg/ops/metrics_session_remove.go: UUID validated before read (line 55), find/write errors wrapped with errors.Wrap (lines 61, 71), no-write on no-match (line 64-68, verified by SHA-256 test), context propagated throughout"
    },
    {
      "concern": "correctness: new CLI command wiring — verify command registration and flag handling",
      "disposition": "addressed",
      "detail": "pkg/cli/cli.go createTaskRemoveMetricsSessionCommand (line 2462): Args=cobra.ExactArgs(2), dispatcher.FirstSuccess pattern, correct JSON/plain output, registered in createTaskCommands at line 1345"
    },
    {
      "concern": "tests: new test coverage — verify edge cases and error paths are covered",
      "disposition": "addressed",
      "detail": "pkg/ops/metrics_session_remove_test.go: 7 Ginkgo tests covering write survivors, no-write on no-match, UUID validation (empty, non-UUID, path-separator), find failure wrap, write failure wrap; integration/cli_test.go AC1-AC7 covers all contract cases"
    },
    {
      "concern": "correctness: metrics domain logic — check metric label/key consistency",
      "disposition": "addressed",
      "detail": "pkg/domain/task_frontmatter_metrics.go: RemoveMetricsSession (line 58) removes all entries matching sessionID, deletes key when len(kept)==0 (line 72-74), coerceMetricsTime handles time.Time/libtime.DateOrDateTime/string (line 187)"
    }
  ]
}
{"verdict":"approve","reason":"chunked review: all 5 chunks approved","concerns_addressed":[{
      "concern": "correctness: auditor \"contradicting itself\" fix — verify logic consistency in guard conditions",
      "disposition": "not-an-issue",
      "detail": "agents/task-auditor.md:244 — guard sentence added as sub-bullet between orphan flag and implementation-level bullets. Contains exact verbatim substring. Guards advice only; threshold unchanged."
    },{
      "concern": "correctness: new operation — check error handling, context propagation, and resource cleanup",
      "disposition": "not-an-issue",
      "detail": "pkg/ops/metrics_session_remove.go — uses errors.Wrapf/Wrap/Errorf, context propagated on all calls, WriteTask called only when removed > 0, uuid.Validate before task read."
    },{
      "concern": "correctness: new CLI command wiring — verify command registration and flag handling",
      "disposition": "not-an-issue",
      "detail": "pkg/cli/cli.go:2461-2509 — cobra.ExactArgs(2), vault dispatcher, PrintJSON for JSON output, nolint:dupl acknowledged, asymmetry in JSON vs plain error paths matches established contract."
    },{
      "concern": "tests: new test coverage — verify edge cases and error paths are covered",
      "disposition": "not-an-issue",
      "detail": "pkg/ops/metrics_session_remove_test.go has 6 specs; pkg/domain/task_frontmatter_metrics_test.go has 5 specs; integration/cli_test.go has 7 AC specs. All ACs pinned with explicit assertions including WriteTaskCallCount==0 on no-match and FindTaskByNameCallCount==0 on invalid UUID."
    },{
      "concern": "correctness: metrics domain logic — check metric label/key consistency",
      "disposition": "not-an-issue",
      "detail": "pkg/domain/task_frontmatter_metrics.go:58-77 — RemoveMetricsSession filters by SessionID, returns 0 on no match without Set, deletes key on last entry, Set with survivors otherwise. Duplicate IDs removed in full."
    },{
      "concern": "correctness: go-composition/no-package-function-calls-in-business-logic (3 findings on task_frontmatter_metrics.go:58,72,75)",
      "disposition": "not-an-issue",
      "detail": "FALSE POSITIVE — ast-grep cannot distinguish receiver methods (f.MetricsSessions(), f.Delete(), f.Set()) from package-level function calls. These are all method calls on *TaskFrontmatter, not pkg.Function(...) calls. Rule incorrectly matched."
    },{
      "concern": "correctness: go-context/cancel-check-in-loop and go-functional-composition/list-checks-ctx-done (2 findings on task_frontmatter_metrics.go:57,61)",
      "disposition": "not-an-issue",
      "detail": "FALSE POSITIVE — RemoveMetricsSession(sessionID string) has no context.Context parameter. There is no ctx to check in the loop. The rule applied to a function signature where context does not exist."
    },{
      "concern": "correctness: RemoveMetricsSession domain logic",
      "disposition": "addressed",
      "detail": "RemoveMetricsSession correctly: (1) calls MetricsSessions() to read current entries, (2) filters by SessionID, (3) returns 0 without writes when nothing removed, (4) calls Delete when last entry is removed, (5) calls Set with survivors otherwise. Implementation matches spec 055."
    },{
      "concern": "correctness: RemoveMetricsSessionOperation validation and error handling",
      "disposition": "addressed",
      "detail": "uuid.Validate called before FindTaskByName (fail-fast), returns error when nothing matches (0 removed), correctly delegates to domain TaskFrontmatter.RemoveMetricsSession. No WriteTask when nothing removed (byte-identical by construction)."
    },{
      "concern": "correctness: CLI command wiring",
      "disposition": "addressed",
      "detail": "createTaskRemoveMetricsSessionCommand properly registered, uses VaultDispatcher.FirstSuccess for multi-vault, handles JSON/text output, wraps errors with context."
    },{
      "concern": "tests: RemoveMetricsSession test coverage",
      "disposition": "addressed",
      "detail": "5 test cases covering: single removal preserves survivor, multi-removal (duplicate id), last-entry deletion (key removed), no-match returns 0 unchanged, absent key returns 0, non-list value returns 0. All domain-level edge cases covered."
    },{
      "concern": "correctness: missing counterfeiter directive on RemoveMetricsSessionOperation interface",
      "disposition": "addressed",
      "detail": "Directive is present at metrics_session_remove.go:20. ast-grep reported it as missing because it looks at the interface line rather than the comment block above it. The generated mocks/remove-metrics-session-operation.go confirms go generate ran successfully."
    },{
      "concern": "correctness: no-bare-error-call in test file (FindTaskByNameReturns/WriteTaskReturns discarding return values)",
      "disposition": "addressed",
      "detail": "These are Counterfeiter-generated mock methods with zero return values (func(...), not func(...) error). The rule's own exemption applies: 'calls that genuinely return nothing'. Suite file pkg/ops/ops_suite_test.go exists so specs are discoverable."
    },{
      "concern": "correctness: package-level function calls (uuid.Validate, errors.*) in Execute",
      "disposition": "not-an-issue",
      "detail": "uuid.Validate and errors package functions are pure utilities with no observable state variation. The struct correctly injects taskStorage (the sole I/O dependency). This is a judgment-level rule; the code is correct as-is."
    },{
      "concern": "tests: edge cases and error paths in RemoveMetricsSessionOperation",
      "disposition": "addressed",
      "detail": "All error paths covered: invalid UUID (empty, non-UUID, path-separator), find failure, write failure, no-match failure. Also covered: survivors written correctly, write not called when nothing matches."
    },{
      "concern": "correctness: auditor \"contradicting itself\" fix — verify logic consistency in guard conditions",
      "disposition": "addressed",
      "detail": "task-auditor.md line 244: guard sentence is strictly between 'Flag orphans as MAJOR' (line 243) and 'Flag implementation-level tasks' (line 245). Text: 'never recommend linking a goal the alignment check will then score as an orphan — recommend theme-only linkage instead and say so explicitly.' Exactly matches the spec AC 8 grep string."
    },{
      "concern": "correctness: new operation — check error handling, context propagation, and resource cleanup",
      "disposition": "addressed",
      "detail": "metrics_session_remove.go: uuid.Validate runs before any read (AC5 structural guarantee); FindTaskByName wraps errors with 'find task'; WriteTask wraps with 'write task'; removed==0 returns error without calling WriteTask (byte-identical guarantee is structural). Context is propagated on all error paths. No resource leaks."
    },{
      "concern": "correctness: new CLI command wiring — verify command registration and flag handling",
      "disposition": "addressed",
      "detail": "cli.go line 1345: command registered as AddCommand alongside append-metrics-session. Uses FirstSuccess dispatcher pattern matching other task mutations. JSON branch returns PrintJSON result (normally nil) before plain branch propagates error — exactly matching the append's established contract. No encoding/json import; no new flags."
    },{
      "concern": "tests: new test coverage — verify edge cases and error paths are covered",
      "disposition": "addressed",
      "detail": "Domain specs (task_frontmatter_metrics_test.go:296-369): removes named entry preserving survivor id+started_at, removes all entries with duplicated id, deletes key when last entry goes, returns 0 when nothing matches, returns 0 on absent/non-list key. Ops specs (metrics_session_remove_test.go): matching id writes once with survivors, non-matching id returns error with id in message and WriteTaskCallCount==0, empty/not-uuid/../escape each return error without calling FindTaskByName, find/write failures are wrapped."
    },{
      "concern": "correctness: metrics domain logic — check metric label/key consistency",
      "disposition": "addressed",
      "detail": "RemoveMetricsSession correctly filters MetricsSessions() on SessionID equality, calls Delete('metrics_sessions') when last entry removed, Set with kept survivors otherwise, returns removed count. coerceMetricsSession skips entries with empty session_id (lenient degradation). All field names consistent with existing append/clear paths."
    },{
      "concern": "correctness: auditor \"contradicting itself\" fix — verify logic consistency in guard conditions",
      "disposition": "addressed",
      "detail": "agents/task-auditor.md line 244: guard clause added at Task-Goal Alignment step 3 — 'When the goal can be marked complete without this task, never recommend linking a goal the alignment check will then score as an orphan — recommend theme-only linkage instead and say so explicitly.'"
    },{
      "concern": "correctness: new operation — check error handling, context propagation, and resource cleanup",
      "disposition": "addressed",
      "detail": "pkg/ops/metrics_session_remove.go: UUID validated before read (line 55), find/write errors wrapped with errors.Wrap (lines 61, 71), no-write on no-match (line 64-68, verified by SHA-256 test), context propagated throughout"
    },{
      "concern": "correctness: new CLI command wiring — verify command registration and flag handling",
      "disposition": "addressed",
      "detail": "pkg/cli/cli.go createTaskRemoveMetricsSessionCommand (line 2462): Args=cobra.ExactArgs(2), dispatcher.FirstSuccess pattern, correct JSON/plain output, registered in createTaskCommands at line 1345"
    },{
      "concern": "tests: new test coverage — verify edge cases and error paths are covered",
      "disposition": "addressed",
      "detail": "pkg/ops/metrics_session_remove_test.go: 7 Ginkgo tests covering write survivors, no-write on no-match, UUID validation (empty, non-UUID, path-separator), find failure wrap, write failure wrap; integration/cli_test.go AC1-AC7 covers all contract cases"
    },{
      "concern": "correctness: metrics domain logic — check metric label/key consistency",
      "disposition": "addressed",
      "detail": "pkg/domain/task_frontmatter_metrics.go: RemoveMetricsSession (line 58) removes all entries matching sessionID, deletes key when len(kept)==0 (line 72-74), coerceMetricsTime handles time.Time/libtime.DateOrDateTime/string (line 187)"
    }]}

@bborbe
bborbe merged commit cd3f495 into master Sep 27, 2026
3 checks passed
@bborbe
bborbe deleted the feat/remove-metrics-session branch September 27, 2026 10:40
bborbe added a commit that referenced this pull request Sep 27, 2026
fix: restore ## Unreleased, which the #224 merge turned into a duplicate v0.149.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant