diff --git a/project/ticket-133/README.md b/project/ticket-133/README.md new file mode 100644 index 0000000..850bb1d --- /dev/null +++ b/project/ticket-133/README.md @@ -0,0 +1,20 @@ +# Ticket 133: Read a Planfile task without status as open, matching Planfile's default + +- **ID**: ticket-133 +- **Owner**: unresolved:human +- **Status**: IN_PROGRESS +- **Workflow state**: EDIT +- **Created**: 2026-10-28 + +## Goal and scope + +`semcod/goal/planfile.yaml` has a legacy task `Q01` without a `status`. monag read it as `unknown`, so `unknown_statuses=1` and autonom fleet admission refused every Willman campaign for semcod/goal with `ambiguous_queue_state`. Planfile itself creates tasks as `open`; monag now uses the same default. + +## Acceptance criteria + +- [x] AC-01: resume tests pass, including a statusless-task regression; governance gate passes. + +## Tracking boundary + +This directory contains the minimal reviewed intent. Optional participant prose +and raw command logs are not required delivery output. diff --git a/project/ticket-133/intent.json b/project/ticket-133/intent.json new file mode 100644 index 0000000..61a7cfc --- /dev/null +++ b/project/ticket-133/intent.json @@ -0,0 +1,75 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-133", + "summary": "Read a Planfile task without status as open, matching Planfile's default", + "workstream": "application", + "classification": { + "kind": "SERVICE", + "priority": "P2", + "origin": "health" + }, + "allowedPaths": [ + "project/ticket-133/**", + "TODO.md", + "project/TICKETS.md", + "src/monag/resume.py", + "tests/test_resume.py" + ], + "forbiddenPaths": [ + "project/ticket-*/user-*.md" + ], + "stacks": [], + "dependsOn": [], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "d50d1bf7d55b304e603cb5e4438cbcbd904f8507", + "targetBranch": "main", + "outcome": "monag resume reads a Planfile task without a status field as open (Planfile's own default) instead of unknown, so one legacy statusless task no longer marks the whole queue ambiguous and blocks autonomous intake", + "nonGoals": [ + "Changing explicit statuses or conflict detection", + "Editing target repositories' planfiles" + ], + "complexity": "XS", + "estimatedMinutes": 10, + "budgets": { + "maxImplementationFiles": 2, + "maxAffectedComponents": 1, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Align the missing-status default with planfile.core (status='open'); explicit unknown values still count as unknown", + "components": [ + { + "name": "resume", + "paths": [ + "src/monag/resume.py", + "tests/test_resume.py" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": { + "impact": "none", + "states": [], + "evidence": [] + }, + "rollback": "Revert the commit" + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-01", + "commands": [ + "python -m unittest tests.test_resume", + "./project/governance-check.sh" + ], + "evidence": "36 resume tests pass including the statusless-task regression; managed gate passes" + } + ] + } +} diff --git a/src/monag/resume.py b/src/monag/resume.py index 809e84b..63b1cb2 100644 --- a/src/monag/resume.py +++ b/src/monag/resume.py @@ -162,7 +162,9 @@ def _load_planfile_yaml_cached(path_str: str, mtime_ns: int): finding=finding, kind='import_evidence', historical=file.stem.startswith(('history-', 'archive-')), ) for finding in evidence) - status = str(item.get('status', 'unknown')).lower() + # Planfile creates tasks as open; a legacy task without a status field + # is unstarted work, not an ambiguous state that blocks the whole queue. + status = str(item.get('status') or 'open').lower() priority = normalize_priority(item.get('priority')) result.append({'id': str(identity), 'status': status, 'title': str(item.get('name', item.get('title', identity))), diff --git a/tests/test_resume.py b/tests/test_resume.py index 542da83..1901f20 100644 --- a/tests/test_resume.py +++ b/tests/test_resume.py @@ -146,6 +146,12 @@ def test_missing_canonical_history_is_incomplete(self): self.assertFalse(result['planfile']['complete']) self.assertTrue(any('canonical history owner unavailable' in e for e in result['errors'])) + def test_task_without_status_is_open_not_unknown(self): + (self.repo / 'planfile.yaml').write_text("tasks:\n- id: Q01\n title: legacy task\n") + queue = self.scan()['projects'][0]['planfile'] + self.assertEqual(queue['unknown_statuses'], 0) + self.assertEqual(queue['remaining_ids'], ['Q01']) + def test_prefixed_ticket_and_path_disagreement(self): self.assertEqual(resume.ticket_identity('ticket/PLF-084-feature'), 'ticket-PLF-084') self.assertEqual(resume.ticket_identity('ticket-115--feature'), 'ticket-115')