allow create-task without an assignee - #14
Conversation
An empty assignee is the operator-inbox signal, so requiring it made a task that is born parked unrepresentable. The pr-watcher's untrusted-author path was rejected every time, so those PRs never reached the queue. status stays required.
There was a problem hiding this comment.
Based on my review, here is the consolidated report and verdict:
PR Review: allow create-task without an assignee
Selector Mode Traceability
- Candidates: ~100+ judgment rules from index (Go files touched)
- Applicable: 0 — The diff makes a targeted validation-change (removes assignee requirement, inverts one test case, updates changelog). No judgment rules are violated by these specific changes.
- Skipped: All judgment rules — their
applies_whenconditions do not match the scope of this narrow bugfix PR (no architectural decisions, no handler changes, no agent/command files, no factory patterns)
Step 3 — Automated Checks
License: LICENSE file present in repo root ✓
Precommit (selector mode): Skipped — selector mode defers to CI for lint+test.
Mechanical Findings (from Step 4a — pre-computed funnel)
The funnel ran over 66 YAMLs and reported 32 findings across task_create_task_executor.go and task_create_task_executor_test.go. All findings are in pre-existing code that this PR did not modify:
| File | Finding | Severity | In PR Diff? |
|---|---|---|---|
task_create_task_executor.go:256 | go-context/cancel-check-in-loop — loop missing ctx.Done() check | SHOULD | No |
task_create_task_executor.go:300 | go-logging/no-log-and-return-error | MUST | No |
task_create_task_executor.go:305 | go-context/cancel-check-in-loop | SHOULD | No |
task_create_task_executor.go:329 | go-context/cancel-check-in-loop + go-logging/no-tight-loop-without-sampler | SHOULD | No |
task_create_task_executor.go:244 | go-logging/no-sensitive-data-in-logs (token in log arg) | MUST | No |
task_create_task_executor.go:476 | go-glog/use-v-for-debug-not-info — bare glog.Infof at V0 | MUST | No |
task_create_task_executor_test.go | go-testing/no-bare-error-call (22 instances) | MUST | No |
task_create_task_executor_test.go:29 | go-testing/suite-test-file-required | MUST | No |
None of these violations are introduced by this PR. They are all in the auto-supersede feature (lines 215–511) and test mock setup that existed before this change. The validateCreateTaskFrontmatter function (lines 189–206) had its assignee check removed — no new violations were introduced.
Step 7 — Manual Review
Changed files reviewed: pkg/command/task_create_task_executor.go, pkg/command/task_create_task_executor_test.go, CHANGELOG.md
validateCreateTaskFrontmatter change (task_create_task_executor.go:201–206):
- The assignee validation block (
if fm.Assignee() == "" { return error }) was removed — correct. statusvalidation remains — correct (still required).- The new 9-line comment is well-written and cites the real incident (
bborbe/git-sync#5).
Test inversion (task_create_task_executor_test.go:129–146):
- The "missing assignee" context is renamed to "empty assignee in frontmatter (task born parked)" — accurately describes the scenario.
- Test now asserts
err.NotTo(HaveOccurred())andCallCount == 1— correct for the new behavior. - Frontmatter uses
status: todo, phase: human_review— matches the github-pr-watcher untrusted-author path described in the PR and the new code comment.
CHANGELOG: Clear, accurate, cites the incident and the doctrine rationale.
No issues found in the PR's actual changes.
Verdict
Must Fix (Critical): None.
Should Fix (Important): None — no issues in PR-touching code.
Nice to Have (Optional): None.
Selector clean — no adjudication needed.
{
"verdict": "approve",
"summary": "PR #14 is a clean, targeted bugfix that removes the overly-strict assignee validation and replaces it with a well-documented comment explaining the operator-inbox doctrine. The only code change is removing 3 lines of validation and adding 9 lines of comment; the test is correctly inverted to assert acceptance rather than rejection. No new violations introduced. All mechanical funnel findings are pre-existing in untouched code.",
"comments": [],
"concerns_addressed": [
"correctness: empty assignee correctly accepted — validateCreateTaskFrontmatter no longer requires assignee; status remains required; vault_scanner already treats empty assignee as unclaimed",
"correctness: status field remains required — unchanged validation; no other required fields were inadvertently modified",
"tests: test inverted from rejection to acceptance with correct frontmatter (status:todo, phase:human_review) matching the github-pr-watcher untrusted-author path"
]
}Uh oh!
There was an error while loading. Please reload this page.
Problem
validateCreateTaskFrontmatterrejected any create-command with an emptyassignee. That makes a task which is born parked unrepresentable.github-pr-watcher's untrusted-author path (pkg/watcher.go:589,buildHumanReviewFrontmatter) deliberately stamps:So every untrusted-author PR produced a command this controller refused:
No task file, no signal on the PR, and the only evidence is that one log line. Observed on bborbe/git-sync#5 (2026-07-28): the watcher logged
published CreateTaskCommand … trusted=falseat the same second, Kafka offset 54177 was consumed, and nothing was ever written. The PR sat atBLOCKEDwith green CI until a human happened to look.Why remove the check rather than change the watcher
An empty assignee is the operator-inbox signal — the "Make Parked Agent Tasks Visible to Operator" doctrine defines escalation as clearing the assignee so no agent claims the task. The controller already honours that everywhere else:
pkg/scanner/vault_scanner.gotreats an empty assignee as unclaimed and dispatches nothingSo this aligns create with update and dispatch. The alternative (watcher stamps a sentinel like
assignee: unassigned) would fork the doctrine and require every inbox query to special-case a magic string.statusremains required.Verification
make precommitgreen: 12 packages, 0 lint issues, 0 vulnerabilities (gosec + trivy + osv-scanner).The test that asserted the old behaviour is inverted to assert the new one — a command with
assigneeabsent,status: todo,phase: human_reviewis now written exactly once.Post-deploy check: an untrusted-author PR should produce a task file with
phase: human_reviewandassignee: "", per gate 11 of the "Agent - Debug Missing PR Reviewer Review" runbook (which previously documented a file that never actually appeared).