feat: add task remove-metrics-session and stop the auditor contradicting itself - #224
Conversation
…(spec 055, prompt 2 of 3)
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.
There was a problem hiding this comment.
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:
-
New
task remove-metrics-sessionverb — removes everymetrics_sessionsentry 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. -
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
removeMetricsSessioninpkg/ops/metrics_session_remove.go:63correctly uses the domainRemoveMetricsSessionwhich 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.mdfix 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:
-
go-context/cancel-check-in-loop(SHOULD): The for-loop over sessions should checkctx.Done()each iteration. -
go-functional-composition/list-checks-ctx-done(MUST): The method iterates without checkingctx.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:duploncreateTaskRemoveMetricsSessionCommandis legitimate — it suppresses duplicate code warnings for a command that is structurally parallel tocreateTaskAppendMetricsSessionCommand(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
RemoveMetricsSessiondomain 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:
pkg/ops/metrics_session_remove.go— new operationpkg/domain/task_frontmatter_metrics.go—RemoveMetricsSessiondomain methodpkg/cli/cli.go—createTaskRemoveMetricsSessionCommandwiringpkg/ops/metrics_session_remove_test.go— unit testspkg/domain/task_frontmatter_metrics_test.go— domain method testsintegration/cli_test.go— 7 AC integration testsagents/task-auditor.md— one-sentence guard fixdocs/work-on-session-lifecycle.md— session lifecycle documentationCHANGELOG.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 callingWriteTask). Uses domainRemoveMetricsSession(not a string-level frontmatter rewrite). No stamp, no clock, noclaude_session_idtouch. Correct. -
pkg/domain/task_frontmatter_metrics.go—RemoveMetricsSessioncorrectly 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 usesdispatcher.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## Unreleasedmatching the PR scope. Version strings unchanged (v0.149.0 is the latest tagged,Unreleasedis 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."
}]}superseded by new automated review
There was a problem hiding this comment.
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.jsonwith glob-matching triggers - Skipped: All rules whose
triggerglob does not match any of the 14 changed files — includes allgo-k8s-*,go-http-service/*,go-cqrs/*,go-k8s-crd/*,go-build-args/*,go-http-handler/*,go-library/*,go-factory/*(nopkg/factory/touched),go-licensing/*(LICENSE present), etc. - Applicable:
go-errors/no-bare-return-err— Go files inpkg/ops/,pkg/cli/,pkg/domain/go-errors/no-context-background-in-business-logic— samego-errors/no-fmt-errorf— samego-doc/exported-item-must-have-comment— all new exported types/functions in new filesgo-architecture/counterfeiter-directive-on-interface— new interfaceRemoveMetricsSessionOperationgo-architecture/new-prefix-constructor-naming—NewRemoveMetricsSessionOperationchangelog/conventional-prefix-required—CHANGELOG.mdchangelog/unreleased-entry-required—CHANGELOG.mdgo-licensing/source-file-header-required— all new.gofilesgo-test-quality-assistantconcerns — test filesgo-context-assistantconcerns — 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.jsonfrom working directory) - All mechanical findings adjudicated as false positives
No Must Fix, Should Fix, or Nice to Have issues found. The implementation is correct:
RemoveMetricsSessionremoves all entries matching a session ID, deletes the key when last entry is removed, and returns 0 when nothing matches- The
RemoveMetricsSessionOperationvalidates 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.goconfirms it was applied. - The
uuid.Validate,errors.Wrapf,errors.Errorf,errors.Wrapcalls 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 onlytaskStorage(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.goexists — the ast-grep finding is a false positive; the test is discoverable. FindTaskByNameReturnsandWriteTaskReturnscalls at lines 36, 44, 116, 130 are Counterfeiter-generated mock methods with zero return values (func(...)notfunc(...) error). They are side-effect setup calls inBeforeEach/Itblocks — 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 operationpkg/ops/metrics_session_remove_test.go— unit testspkg/domain/task_frontmatter_metrics.go— domain logicpkg/cli/cli.go— CLI command wiringagents/task-auditor.md— auditor fix (1-line addition)docs/work-on-session-lifecycle.md— lifecycle docsintegration/cli_test.go— integration testsCHANGELOG.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-57validates 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.goAC4 using SHA-256 comparison — correct. RemoveMetricsSessiondomain method correctly deletes the key when the last entry is removed (task_frontmatter_metrics.go:72-74).- The
task-auditor.mdone-line fix (line 244) correctly prevents the self-contradicting recommendation by adding a guard clause. docs/work-on-session-lifecycle.mdis 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)"
}]}fix: restore ## Unreleased, which the #224 merge turned into a duplicate v0.149.1
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 everymetrics_sessionsentry carrying that session id, preserving every other entry and every other frontmatter key. It is the counterpart ofappend-metrics-sessionand the only path that clears one entry by id.claude_session_id.2.
task-auditorno 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_sessionsto theknownTaskListFieldsallowlist is inert, for three mechanical reasons — each verified against the tree:metricsSessionsWriteRefusalruns atpkg/ops/frontmatter_entity.go:743, before the allowlist check at:750, so the refusal still fires and the entry changes nothing.:760-768reads onlyGoals()/Tags()/BlockedBy()— all[]string— so a map-valued field falls through setting nothing.addandremove, so the entry would also opentask add metrics_sessions ….The refusal introduced in v0.147.0 stays absolute:
metricsSessionsWriteRefusalandknownTaskListFieldsare 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
clearpath 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.gogains aDescribe("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.docs/dod.mdrequires it).mocks/remove-metrics-session-operation.gois generated, not hand-written; the generator's header-stripping ofmocks/mocks.gowas not carried.Pipeline note
Authored as three dark-factory prompts, each audited by
prompt-auditorbefore 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.