From 0c044a6704a3419b527ccd9a387524190d18e0dc Mon Sep 17 00:00:00 2001 From: Zayn329 <94752636+Zayn329@users.noreply.github.com> Date: Mon, 7 Sep 2026 10:38:28 +0000 Subject: [PATCH 1/4] Add AGENTS.md and harness_learning documentation Add standing knowledge (AGENTS.md) and harness learning artifacts for task priority feature planning (exploration report, implementation plan, and micro context). Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- AGENTS.md | 130 ++++++++++++++++++++++++ harness_learning/exploration_report.md | 83 +++++++++++++++ harness_learning/implementation_plan.md | 72 +++++++++++++ harness_learning/micro_context.md | 56 ++++++++++ 4 files changed, 341 insertions(+) create mode 100644 AGENTS.md create mode 100644 harness_learning/exploration_report.md create mode 100644 harness_learning/implementation_plan.md create mode 100644 harness_learning/micro_context.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..9352860 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,130 @@ +# AGENTS.md — Standing Knowledge & Instructions + +## 1. Project Purpose & Scope +**Task-Manager** is a task and project management web application built with Python and Flask. It allows users to organize tasks under project tabs, manage open/closed task statuses, rename projects and tasks, and interact through either a web browser interface or a RESTful JSON API documented via Swagger. + +--- + +## 2. Verified Technology Stack +*(Source of truth: `pyproject.toml`, `task_manager/__init__.py`, `task_manager/app.py`)* + +* **Language**: Python (`>=3.13` as declared in `pyproject.toml`) +* **Web Framework**: Flask 3.1.3 +* **Database & ORM**: SQLite (`ctm.db`), Flask-SQLAlchemy 3.1.1, SQLAlchemy 2.0.41 +* **API Documentation**: Flasgger 0.9.7.1 (Swagger UI at `/apidocs/`) +* **Frontend**: HTML5, Jinja2 3.1.6, Bootstrap 3.3.7 (CDN), jQuery 1.12.4 (CDN), custom UX script (`ux.js`) +* **Test Suite**: `pytest` 9.0.3, `pytest-cov` 6.2.1 + +--- + +## 3. Project Entry Points & Running +* **Development Server**: `python task_manager/app.py` or `make dev` (Runs Flask dev server on `http://localhost:5000`) +* **Production Server**: `make prod` (Runs Gunicorn server on `http://localhost:8000`) +* **Interactive API Documentation**: `http://localhost:5000/apidocs/` +* **Application Factory**: `task_manager/__init__.py:create_app()` + +--- + +## 4. Test Execution & Quality Assurance +The project supports standard Python environment runners. When using `uv` in this sandbox environment: +* **Run All Tests**: `uv run pytest` +* **Run with Coverage**: `uv run pytest --cov=task_manager --cov-report=term-missing` +* **Code Formatting / Type Checks** (configured in `pyproject.toml`): + ```bash + uv run black --check task_manager tests + uv run isort --check task_manager tests + uv run mypy task_manager + ``` + +--- + +## 5. Architecture & Execution Flow + +``` + ┌─────────────────────────┐ + │ USER / HTTP CLIENT │ + └────────────┬────────────┘ + │ + ┌─────────────────┴─────────────────┐ + │ │ + ▼ ▼ + [ WEB UI REQUESTS ] [ REST API REQUESTS ] + e.g., GET /, POST /add e.g., GET /api/tasks, + GET /project/ POST /api/tasks, PUT /api/... + │ │ + └─────────────────┬─────────────────┘ + │ + ▼ + [ Flask Blueprint Routes ] + (task_manager/routes.py) + │ + ┌───────────────────────────┴───────────────────────────┐ + │ │ + ▼ ▼ +[ Jinja2 View Renderer ] [ JSON Response ] +(task_manager/templates/index.html) (Flask jsonify) + │ │ + └───────────────────────────┬───────────────────────────┘ + │ + ▼ + [ SQLAlchemy ORM Models ] + (task_manager/models.py) + ├── Projects (project_id, project_name, active, url_slug) + └── Tasks (task_id, project_id, task, status) + │ + ▼ + [ SQLite Database ] + (instance/ctm.db) +``` + +--- + +## 6. Repository Map + +``` +task-manager/ +├── task_manager/ +│ ├── __init__.py # Application factory (create_app) & DB initialization +│ ├── app.py # Main entrypoint with Flasgger Swagger initialization +│ ├── models.py # Database models (Projects, Tasks) +│ ├── routes.py # Web UI routes & REST API endpoints +│ ├── templates/ +│ │ └── index.html # Jinja2 template for web interface +│ └── static/ +│ └── js/ +│ └── ux.js # Client-side JavaScript interactions +├── tests/ +│ ├── conftest.py # Pytest fixtures (app, client, create_project, create_task) +│ ├── test_models.py # ORM Model unit tests +│ ├── test_routes.py # Web route integration tests +│ ├── test_api.py # Web API integration tests +│ └── test_rest.py # REST API unit tests +├── harness_learning/ # Exploration reports, implementation plans, and micro-contexts +├── pyproject.toml # Project metadata, dependencies, and tool settings +├── Makefile # Target commands (dev, prod, test, clean) +└── REST_README.md # REST API usage documentation +``` + +--- + +## 7. Development Conventions +1. **Preserve Existing Signatures**: Ensure function and model parameter lists retain backwards compatibility to prevent breaking callers and test fixtures. +2. **Explicit Form & JSON Fallbacks**: Route handlers processing `request.form` or `request.get_json()` must handle missing keys gracefully using fallbacks. +3. **ORM Model Methods**: Domain logic and slug generation belong directly on model classes in `models.py`. +4. **Clean Commits**: Commit messages should follow standard Git conventions (short subject line under 50 characters, blank line, clear body detailing reasoning). + +--- + +## 8. What NOT To Do (Negative Constraints) +* **DO NOT** modify codebase files during exploration phases when only research or planning is requested. +* **DO NOT** write code without progressive exploration and context gathering first. +* **DO NOT** introduce heavy external dependencies (e.g. migration frameworks or custom enum libraries) when simple Python standard types suffice. +* **DO NOT** state claims as verified truth without citing inspected files or test output. + +--- + +## 9. Verification Instructions +Before declaring any task complete, perform three levels of verification: +1. **Behavioral Verification**: Confirm that the implemented requirement actually works end-to-end as intended in runtime execution, not merely that automated tests exist. +2. **Regression & Test Verification**: Execute `uv run pytest` to verify that relevant unit and integration tests pass and no regressions were introduced. +3. **Repository State Verification**: Run `git status` to confirm that only intended files were modified or created. diff --git a/harness_learning/exploration_report.md b/harness_learning/exploration_report.md new file mode 100644 index 0000000..3f9b133 --- /dev/null +++ b/harness_learning/exploration_report.md @@ -0,0 +1,83 @@ +# Exploration Report: Task Priority Feature + +## 1. Boundary & Exploration Scope Constraint +* **Boundary Rule**: Source code (`task_manager/`, `tests/`) was strictly preserved without modification during exploration. +* **Artifact Scope**: This document in `harness_learning/` is generated specifically to capture exploration findings and structural dependencies as requested. + +--- + +## 2. Observed Repository Facts vs Inferences vs Proposed Assumptions + +### A. Observed Repository Facts (Grounded in Code Inspection) +1. **`task_manager/models.py`**: + * `Tasks` table schema currently has columns: `task_id` (Integer, Primary Key), `project_id` (Integer, ForeignKey), `task` (Text), `status` (Boolean, default False). + * `Tasks.__init__(self, project_id, task, status=True)` initializes these attributes. +2. **`task_manager/routes.py`**: + * `/add` (`POST`) retrieves `task = request.form.get("task")`, `project = request.form.get("project")`, `status = bool(int(request.form.get("status")))`. + * `/api/tasks` (`GET`) serializes tasks into dictionaries with keys `id`, `project_id`, `task`, `status`. + * `/api/tasks` (`POST`) accepts `project_id`, `task`, `status` from JSON payload. + * `/api/tasks/` (`PUT`) updates `task` and `status` from JSON payload. +3. **`conftest.py`**: + * `create_task` fixture calls `Tasks(project_id=project.project_id, task=task_desc, status=status)`. + +### B. Inferences (Derived Architectural Relationships) +1. Adding a new attribute to `Tasks` requires synchronized updates across ORM model attributes, form parsing, JSON serialization/deserialization, and test fixtures. +2. Form handlers use `request.form.get()` which defaults to `None` if a form parameter is missing; API endpoints use `request.get_json()` which requires dict key checking. + +### C. Proposed Implementation Assumptions (Future Design Choices) +1. Task priority will be stored as a string field (`"Low"`, `"Medium"`, `"High"`) with a default value of `"Medium"`. +2. All existing tasks and legacy API requests without explicit priority will automatically default to `"Medium"`. + +--- + +## 3. Structural Dependency Relationships vs Runtime Execution Flow + +### A. Structural Dependency Relationships +* **`task_manager/models.py:Tasks`** + └── Dependent on: `db.Model` (SQLAlchemy) +* **`task_manager/routes.py`** + ├── Dependent on: `task_manager/models.py:Tasks` + ├── Dependent on: `task_manager/models.py:Projects` + └── Dependent on: `task_manager/templates/index.html` +* **`tests/conftest.py`** + └── Dependent on: `task_manager/models.py:Tasks` +* **`tests/test_routes.py`, `tests/test_api.py`, `tests/test_rest.py`** + └── Dependent on: `conftest.py` fixtures and `routes.py` endpoints + +### B. Runtime Execution Flow for Task Operations + +``` +[ Web UI Form Submission ] [ REST API JSON Request ] + POST /add POST /api/tasks + │ │ + ▼ ▼ +Extract form fields Extract JSON fields + (task, project, status) (project_id, task, status) + │ │ + └───────────────────────┬────────────────────────┘ + │ + ▼ + Instantiate Tasks Model + Tasks(project_id, task, status) + │ + ▼ + SQLAlchemy DB Session Commit + db.session.add() & db.session.commit() + │ + ┌───────────────────────┴────────────────────────┐ + │ │ + ▼ ▼ +Redirect to / (Render index.html) Return 201 Created JSON Payload +``` + +--- + +## 4. Grounding Verification Matrix + +| Claim in Exploration Report | Inspected File & Line Evidence | Verification Status | +| :--- | :--- | :--- | +| `Tasks` model has `task_id`, `project_id`, `task`, `status` | `task_manager/models.py` (lines 28-34) | **Grounded** | +| `/add` route handles task creation via form data | `task_manager/routes.py` (lines 43-85) | **Grounded** | +| `/api/tasks` GET endpoint serializes task fields | `task_manager/routes.py` (lines 191-213) | **Grounded** | +| `create_task` test fixture instantiates `Tasks` | `conftest.py` (lines 38-46) | **Grounded** | +| Working tree is clean and 55 pytest tests pass | Terminal command `uv run pytest` output | **Grounded** | diff --git a/harness_learning/implementation_plan.md b/harness_learning/implementation_plan.md new file mode 100644 index 0000000..f3ff872 --- /dev/null +++ b/harness_learning/implementation_plan.md @@ -0,0 +1,72 @@ +# Implementation Plan: Task Priority Feature + +## 1. Discovered Repository Facts vs Proposed Design Choices + +### A. Discovered Repository Facts +1. Tasks currently possess `task_id`, `project_id`, `task`, and `status`. +2. Task creation occurs in two routes: `/add` (Web HTML form) and `/api/tasks` (REST JSON API). +3. The test suite uses a shared fixture `create_task` in `conftest.py` which passes positional/keyword arguments to `Tasks(...)`. +4. The database is initialized via `db.create_all()` in `task_manager/__init__.py`. + +### B. Proposed Design Choices (Task Priority Feature) +1. **Priority Values**: Represented as strings: `"Low"`, `"Medium"`, `"High"`. +2. **Default Priority**: Set to `"Medium"` across models, web forms, and REST endpoints. +3. **Database Representation**: `db.Column(db.String(10), default="Medium")`. + +--- + +## 2. Multi-Dimensional Backward Compatibility Analysis + +To guarantee that adding priority introduces zero regressions across existing code and tests: + +1. **Model Constructor Compatibility**: + * *Strategy*: `Tasks.__init__(self, project_id, task, status=True, priority="Medium")` + * *Impact*: Existing calls like `Tasks(project_id, task)` or `Tasks(project_id, task, status)` continue working without argument count mismatches. +2. **Test Fixture Compatibility**: + * *Strategy*: If `Tasks.__init__` has a default parameter `priority="Medium"`, existing test fixtures like `create_task` in `conftest.py` automatically work without requiring mandatory changes. +3. **API Payload Compatibility**: + * *Strategy*: `GET /api/tasks` includes `"priority"` as an additive key. `POST /api/tasks` and `PUT /api/tasks/` use `.get("priority", "Medium")` and `.get("priority", task.priority)` respectively. + * *Impact*: Clients omitting `"priority"` in JSON payloads continue functioning seamlessly. +4. **Database & Schema Compatibility**: + * *Strategy*: New SQLite instances created via `db.create_all()` include the `priority` column automatically. For existing development databases, falling back gracefully or recreating the test DB handles the change cleanly. +5. **Form Input & Rendering Compatibility**: + * *Strategy*: `request.form.get("priority", "Medium")` safely defaults if an old form submission lacks the input. The Jinja2 template checks for `task.priority` or displays default styling. + +--- + +## 3. Justification of Minimum Change Against Alternatives + +| Proposed Approach | Alternative 1: Integer Priority Levels (1, 2, 3) | Alternative 2: Custom DB Enum / PostgreSQL Enum | Alternative 3: Separate Priority Table | Alternative 4: Migration Framework (Alembic) | +| :--- | :--- | :--- | :--- | :--- | +| **Choice**: String (`"Low"`, `"Medium"`, `"High"`) | **Rejected**: Requires mapping integers to human-readable labels in UI and API docs. | **Rejected**: SQLite does not natively support SQL ENUM types; requires dialect-specific workarounds. | **Rejected**: Creates unnecessary join queries (`JOIN priority`) for a simple 3-level attribute. Overengineers data model. | **Rejected**: Project uses `db.create_all()` without Alembic migration infrastructure. Introducing Alembic adds unnecessary complexity. | +| **Justification**: Storing strings (`String(10)`) is human-readable, natively supported by SQLite/SQLAlchemy, and requires zero extra dependencies. | + +--- + +## 4. Behavior-Oriented Acceptance Criteria (Definition of Done) + +The implementation will be considered complete **ONLY** when the following externally observable behaviors are satisfied: + +* **AC 1 (Default Priority Assignment)**: + When a task is created without specifying priority (via Web UI or REST API), the system assigns it `"Medium"` priority. +* **AC 2 (Explicit Priority Creation via Web UI)**: + When a user selects `"High"` or `"Low"` priority in the web form and submits, the created task reflects that priority in the task list. +* **AC 3 (Explicit Priority Creation via REST API)**: + When a JSON payload containing `{"priority": "High"}` is POSTed to `/api/tasks`, the returned 201 response payload contains `"priority": "High"`. +* **AC 4 (Priority Updates via REST API)**: + When a JSON payload containing `{"priority": "Low"}` is PUT to `/api/tasks/`, subsequent GET requests to `/api/tasks/` return `"priority": "Low"`. +* **AC 5 (REST API Payload Contract)**: + All task objects returned by `GET /api/tasks` and `GET /api/tasks/` contain the `"priority"` key. +* **AC 6 (Zero Regression Guarantee)**: + All 55 pre-existing unit tests pass without failure or modification of existing test logic. + +--- + +## 5. Implementation Task List (Separated from Acceptance Criteria) +*(To be executed only when feature development begins)* + +1. Add `priority` column to `Tasks` in `task_manager/models.py`. +2. Update `/add` form handling in `task_manager/routes.py`. +3. Update REST endpoints (`/api/tasks`) in `task_manager/routes.py`. +4. Update web UI template `task_manager/templates/index.html`. +5. Add unit tests for priority behavior in `tests/`. diff --git a/harness_learning/micro_context.md b/harness_learning/micro_context.md new file mode 100644 index 0000000..8aae87e --- /dev/null +++ b/harness_learning/micro_context.md @@ -0,0 +1,56 @@ +# Task Priority Feature: Micro Context & Guardrails + +## 1. Role Delineation of Harness Artifacts +* **`AGENTS.md`**: Standing project knowledge, environment conventions, and permanent agent directives. +* **`harness_learning/exploration_report.md`**: Grounded repository evidence, structural dependencies, and execution flow. +* **`harness_learning/implementation_plan.md`**: Task intent, minimal design choices, and behavioral acceptance criteria. +* **`harness_learning/micro_context.md`**: Targeted code symbols, inspection vs modification boundaries, and quantitative debugging protocols. + +--- + +## 2. Symbol-Level Target Mapping + +| Target Symbol / Function | File Location | Purpose & Action | +| :--- | :--- | :--- | +| `class Tasks(db.Model)` | `task_manager/models.py` | Add `priority` Column definition and update `__init__` constructor signature with default `priority="Medium"`. | +| `def add_task()` | `task_manager/routes.py` | Extract `request.form.get("priority", "Medium")` and pass to `Tasks`. | +| `def api_get_tasks()` & `api_get_task()` | `task_manager/routes.py` | Add `"priority": t.priority` to JSON serialization dict. | +| `def api_create_task()` | `task_manager/routes.py` | Extract `data.get("priority", "Medium")` from JSON body when creating task. | +| `def api_update_task()` | `task_manager/routes.py` | Update `task.priority = data.get("priority", task.priority)` from JSON body. | +| Form & Table HTML snippets | `task_manager/templates/index.html` | Add ` + Priority +
  @@ -148,6 +154,7 @@

  DESCRIPTION + PRIORITY STATUS @@ -174,6 +181,11 @@

  {% endif %} + + + {{ task.priority }} + + {% if task.status %} diff --git a/tests/test_models.py b/tests/test_models.py index 25e8fdd..7199af5 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -8,3 +8,22 @@ def test_task_model_repr(app, create_task): task = create_task(task_desc="Test Task") with app.app_context(): assert repr(task) == f"" + + +def test_task_model_priority_default(app, create_task): + task = create_task(task_desc="Default Priority Task") + with app.app_context(): + assert task.priority == "Medium" + + +def test_task_model_priority_explicit(app, create_project): + from task_manager import db + from task_manager.models import Tasks + + project = create_project(name="Priority Project") + task = Tasks(project_id=project.project_id, task="Urgent Task", status=True, priority="High") + db.session.add(task) + db.session.commit() + + with app.app_context(): + assert task.priority == "High" diff --git a/tests/test_rest.py b/tests/test_rest.py index bbb1238..660ccc6 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -52,6 +52,7 @@ def test_get_tasks(client, create_task): assert len(data) == 1 assert data[0]["id"] == task.task_id assert data[0]["task"] == "Task1" + assert data[0]["priority"] == "Medium" def test_get_task_valid(client, create_task): @@ -61,6 +62,7 @@ def test_get_task_valid(client, create_task): assert response.status_code == 200 assert data["id"] == task.task_id assert data["task"] == "Task1" + assert data["priority"] == "Medium" def test_get_task_invalid(client): @@ -86,13 +88,23 @@ def test_create_project_fail(client): def test_create_task_success(client, create_project): project = create_project("P", True) - payload = {"project_id": project.project_id, "task": "New Task", "status": False} + payload = { + "project_id": project.project_id, + "task": "New Task", + "status": False, + "priority": "High", + } response = client.post("/api/tasks", json=payload) data = json.loads(response.data) assert response.status_code == 201 assert "id" in data assert data["message"] == "Task created" + created_id = data["id"] + get_res = client.get(f"/api/tasks/{created_id}") + task_data = json.loads(get_res.data) + assert task_data["priority"] == "High" + def test_create_task_fail(client): response = client.post("/api/tasks", json={"task": "No project"}) @@ -124,7 +136,7 @@ def test_update_project_fail(client): def test_update_task_success(client, create_task, app): task = create_task("OldTask", True) - payload = {"task": "NewTask", "status": False} + payload = {"task": "NewTask", "status": False, "priority": "Low"} response = client.put(f"/api/tasks/{task.task_id}", json=payload) data = json.loads(response.data) assert response.status_code == 200 @@ -134,6 +146,7 @@ def test_update_task_success(client, create_task, app): updated = db.session.get(Tasks, task.task_id) assert updated.task == "NewTask" assert updated.status is False + assert updated.priority == "Low" def test_update_task_fail(client): diff --git a/tests/test_routes.py b/tests/test_routes.py index 9455fca..d3e784e 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -111,6 +111,24 @@ def test_add_task_existing_project_used(client, app): assert task.task == "Task X" +def test_add_task_with_explicit_priority(client, app): + response = client.post( + "/add", + data={ + "task": "High Priority Task", + "project": "Work", + "status": "1", + "priority": "High", + }, + ) + assert response.status_code == 302 + + with app.app_context(): + task = Tasks.query.filter_by(task="High Priority Task").first() + assert task is not None + assert task.priority == "High" + + # Test /close From 49f2aeda283425662dd0da8cf587bd1784691029 Mon Sep 17 00:00:00 2001 From: Zayn329 <94752636+Zayn329@users.noreply.github.com> Date: Mon, 7 Sep 2026 12:36:22 +0000 Subject: [PATCH 3/4] Audit and refine Task Priority implementation with validation and safe payload handling Add priority validation (Low, Medium, High) with automatic fallback to 'Medium' and safe payload extraction for Web UI form submissions and REST API requests. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- task_manager/models.py | 5 ++++- task_manager/routes.py | 11 ++++++++--- tests/test_models.py | 13 +++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/task_manager/models.py b/task_manager/models.py index 03fe3de..f2eb882 100644 --- a/task_manager/models.py +++ b/task_manager/models.py @@ -25,6 +25,9 @@ def __repr__(self): return "".format(self.project_name) +VALID_PRIORITIES = {"Low", "Medium", "High"} + + class Tasks(db.Model): """Tasks schema""" @@ -38,7 +41,7 @@ def __init__(self, project_id, task, status=True, priority="Medium"): self.project_id = project_id self.task = task self.status = status - self.priority = priority + self.priority = priority if priority in VALID_PRIORITIES else "Medium" def __repr__(self): return f"" diff --git a/task_manager/routes.py b/task_manager/routes.py index 3cb7432..58931eb 100644 --- a/task_manager/routes.py +++ b/task_manager/routes.py @@ -85,6 +85,8 @@ def add_task(): status = bool(int(request.form.get("status"))) priority = request.form.get("priority", "Medium") + if priority not in {"Low", "Medium", "High"}: + priority = "Medium" # add the new task new_task = Tasks(project_id, task, status, priority) @@ -376,10 +378,12 @@ def api_create_task(): 201: description: Task created """ - data = request.get_json() + data = request.get_json() or {} if not data or "task" not in data or "project_id" not in data: return jsonify({"error": "Missing task or project_id"}), 400 priority = data.get("priority", "Medium") + if priority not in {"Low", "Medium", "High"}: + priority = "Medium" task = Tasks(data["project_id"], data["task"], data.get("status", True), priority) db.session.add(task) db.session.commit() @@ -448,13 +452,14 @@ def api_update_task(id): 200: description: Task updated """ - data = request.get_json() + data = request.get_json() or {} task = db.session.get(Tasks, id) if not task: return jsonify({"error": "Task not found"}), 404 task.task = data.get("task", task.task) task.status = data.get("status", task.status) - task.priority = data.get("priority", task.priority) + if "priority" in data and data["priority"] in {"Low", "Medium", "High"}: + task.priority = data["priority"] db.session.commit() return jsonify({"message": "Task updated"}), 200 diff --git a/tests/test_models.py b/tests/test_models.py index 7199af5..cf33924 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -27,3 +27,16 @@ def test_task_model_priority_explicit(app, create_project): with app.app_context(): assert task.priority == "High" + + +def test_task_model_priority_invalid_fallback(app, create_project): + from task_manager import db + from task_manager.models import Tasks + + project = create_project(name="Invalid Priority Project") + task = Tasks(project_id=project.project_id, task="Invalid Task", status=True, priority="Urgent") + db.session.add(task) + db.session.commit() + + with app.app_context(): + assert task.priority == "Medium" From b3a6a3018f29a6e712776cedd563f9e4d25218a6 Mon Sep 17 00:00:00 2001 From: Zayn329 <94752636+Zayn329@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:07:38 +0000 Subject: [PATCH 4/4] Add specification for Task Due Dates feature Add harness_learning/due_date_spec.md defining requirements, contracts, blast radius, overdue formatting (DD/MM in red), and test strategies for adding optional due dates to tasks. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- harness_learning/due_date_spec.md | 99 +++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 harness_learning/due_date_spec.md diff --git a/harness_learning/due_date_spec.md b/harness_learning/due_date_spec.md new file mode 100644 index 0000000..42ced59 --- /dev/null +++ b/harness_learning/due_date_spec.md @@ -0,0 +1,99 @@ +# Specification: Task Due Dates Feature + +## 1. Overview & Purpose +This specification defines the requirement for adding an **optional Due Date** field to tasks in the Task-Manager application. When specified, the due date is displayed directly in front of the task description in `DD/MM` format. If the due date has passed, the due date label turns **red**. Tasks created without a due date (and all pre-existing tasks in the database) default to showing `"Unassigned"`. + +--- + +## 2. Core Requirements & Scope Boundaries + +### Included Features: +1. **Optional Due Date Input**: User can optionally select or enter a due date during task creation via Web UI or REST API. +2. **Display Format**: Rendered in `DD/MM` format (e.g. `25/12`) directly in front of the status checkbox / task action icons. +3. **Unassigned Fallback**: Tasks without a due date display `"Unassigned"`. All existing records in the database inherit `"Unassigned"`. +4. **Overdue Highlighting**: If the current date exceeds the task's due date, the due date text/badge renders in **red** (e.g., Bootstrap CSS `text-danger` or `label-danger`). +5. **REST API & Swagger Integration**: `due_date` field exposed in GET, POST, and PUT API responses/payloads. + +### Explicit Negative Constraints (Out of Scope): +* **NO Reminders**: Do NOT build email, push, or popup reminder functionality. +* **NO Notifications**: Do NOT send background notifications or queue system messages. +* **NO Recurring Schedules**: Do NOT build recurring due date logic or calendar sync integrations. + +--- + +## 3. Interfaces & Data Contracts + +### A. Database Schema (`task_manager/models.py`) +* **New Column**: `due_date = db.Column(db.String(10), default="Unassigned")` +* **Model Constructor**: + ```python + def __init__(self, project_id, task, status=True, priority="Medium", due_date="Unassigned"): + self.project_id = project_id + self.task = task + self.status = status + self.priority = priority + self.due_date = due_date if due_date else "Unassigned" + ``` + +### B. Web Interface (`task_manager/templates/index.html` & `routes.py`) +1. **Creation Form**: + * Add optional date input field in task form: + `` +2. **Task Table Display**: + * Position: Rendered just before the status check icon / column in `index.html`. + * Template Logic: + ```jinja2 + {% if task.due_date and task.due_date != "Unassigned" and is_overdue(task.due_date) %} + {{ task.due_date }} + {% else %} + {{ task.due_date }} + {% endif %} + ``` + +### C. REST API Contracts (`task_manager/routes.py`) +1. **`GET /api/tasks` & `GET /api/tasks/`**: + * Response payload key: `"due_date": "25/12"` or `"due_date": "Unassigned"`. +2. **`POST /api/tasks`**: + * Optional JSON property: `"due_date": "25/12"`. If omitted or null, defaults to `"Unassigned"`. +3. **`PUT /api/tasks/`**: + * Optional JSON property: `"due_date": "25/12"`. Updates task due date if provided. + +--- + +## 4. Blast Radius Analysis & Risk Mitigation + +| Component | Blast Radius Risk | Mitigation Strategy | +| :--- | :--- | :--- | +| **`Tasks.__init__` Constructor** | **High**: Adding `due_date` as a required parameter breaks all existing model instantiations in routes and unit test fixtures. | Make `due_date="Unassigned"` an optional keyword argument with default value. | +| **Database Backward Compatibility** | **High**: Existing rows in `ctm.db` will have `NULL` or missing `due_date` values. | Python property getter / helper method treats `None` or missing value as `"Unassigned"`. | +| **Date Parsing Mismatch** | **Medium**: Users or API clients submitting dates in `YYYY-MM-DD` vs `DD/MM` formats. | Standardize formatting logic helper `format_due_date()` in Python to format valid dates to `DD/MM` and fall back safely to `"Unassigned"`. | +| **Overdue Comparison** | **Medium**: Date comparison logic failing across month boundaries or leap years. | Parse `DD/MM` with current year context using Python `datetime` for overdue comparison (`task_date < today`). | + +--- + +## 5. Verification & Test Strategy + +To verify feature correctness without regressions: + +1. **Model Tests (`tests/test_models.py`)**: + * Verify default `due_date` is `"Unassigned"`. + * Verify explicit `due_date` storing (e.g. `"15/08"`). +2. **Web Route & Overdue Styling Tests (`tests/test_routes.py`)**: + * Verify task creation with and without `due_date`. + * **Mandatory Test**: Verify that if a due date has passed (e.g., yesterday's date formatted as `DD/MM`), the rendered HTML contains the `text-danger` class or red styling indicator. +3. **REST API Tests (`tests/test_rest.py`)**: + * Verify `GET /api/tasks` returns `"due_date"` field for all records. + * Verify `POST /api/tasks` accepts `"due_date"`. + * Verify `PUT /api/tasks/` updates `"due_date"`. + +--- + +## 6. Acceptance Criteria (Definition of Done) + +* **AC 1**: Tasks created without a due date show `"Unassigned"`. +* **AC 2**: Pre-existing tasks in the database display `"Unassigned"`. +* **AC 3**: Due dates display in `DD/MM` format positioned before the status check icon. +* **AC 4**: When a task due date is in the past, it renders in **red** text/style on the UI. +* **AC 5**: REST API GET, POST, and PUT endpoints support `"due_date"`. +* **AC 6**: Automated test asserts that overdue tasks render with red styling indicator. +* **AC 7**: Zero reminders, notifications, or extraneous features are added.