Keep a task's scheduled day separate from its deadline and reminder
A fictional Google Tasks intent map keeps the API due date separate from an exact deadline, reminder, assignment acknowledgement and underlying work evidence. Local reproduction does not establish account behavior.
Immutable revision: 5283df40db865c6749ba777c9643fd32e8af558e946d9cd5f0420a23a3fd8d4b. Publication and independent validation are separate; inspect metadata and provenance before use.
This is a historical revision. Read current publication
Keep a task's scheduled day separate from its deadline and reminder
An owner wants a reading packet started on November 1 and ready by November 3, with a separate reminder. A task snapshot has a November 1 due value, document assignment context and a completed label. The useful handoff preserves the three time meanings and asks for the missing assignee, acceptance and receipt evidence. It cannot establish that the owner received the packet.
Fictional offline example. Every role, record, link and clock below is invented. The snapshot is an API-shaped teaching subset, not a captured Google response. The example prepares an unsent inventory; it creates no task, assignment or alert.
What the fields support
The current Workspace Task resource, checked October 5, 2026 UTC (visible update February 24, 2026), describes due as a scheduled day rather than a deadline. It retains the date and discards the time; the API cannot use it to read or write a scheduled clock time. Do not replace the owner's November 1 schedule with November 3 merely because the field is named due.
The official v1 discovery document, revision 20260927, agrees and has no separate structured deadline or reminder property in its inspected Task inventory. This API finding does not establish what every client UI supports. Preserve unsupported intent separately rather than silently dropping it.
The resource also defines status/completed as task-state evidence and assignmentInfo as read-only assignment-source context for tasks assigned to the current user. In this fictional snapshot the account subject is unknown. A document identifier neither binds the proposed role to that subject nor records their acknowledgement. A completed task label does not meet this owner's separate criterion: receipt of the reading packet.
| Supplied item | Preserve | Leave unresolved |
|---|---|---|
Scheduled day November 1; due encoded at midnight UTC |
Scheduled calendar-day component | Any actual scheduled time or account write |
| Deadline day November 3, owner day context New York | Calendar date and context | Exact cutoff instant; no guessed midnight or end of day |
Reminder 2026-11-02T14:00:00Z |
The supplied explicit UTC instant | Any alert delivery; no local-zone conversion is performed |
| Proposed assistant; document assignment context | Proposal and reported source context separately | Account identity, current assignee and acceptance |
Completed label at 2026-11-02T15:00:00Z; no receipt |
Task label and its timestamp | Underlying work and lateness |
The pinned task-handoffs standard [current article] governs the profile below. This is a fresh adaptation of the retained unpublished date/reminder draft by owner:bootstrap, entry 6429e169-b936-4d84-ae8a-fad0625e958d, candidate 20c7220f33f7230b27581ed44eb95be2f2bc0fc02a2d11da6cc770eeb85ba20f (October 3, 2026). Its earlier observations are historical and are not certified again here. The reminder is now supplied directly in UTC to keep this case focused on representation and evidence.
Reproduce the inventory
Copy each of the four named fences below to a file of the same name in one empty directory. Preserve UTF-8 bytes and one final LF per file. Python 3.12.3 ran the actual checks; no third-party packages are needed. check-task.py checks all 15 output fields, the full expected output bytes, three positive cases and 27 rejection cases. Each rejection is a limit of this local subset, not a prediction that Google would reject that input. The report includes actual UTC execution time and runtime details.
The two additional positive cases show that missing assignment context remains unknown and a needsAction label still leaves the work unresolved. Counterexamples include missing or malformed dates, missing reminder zone/day context/proposed assignee/evidence slots, deadline substituted for schedule, changed snapshot pin, wrong task, changed owner/proposed role/work criterion, all-future scope, stale acknowledgement, new receipt requiring evaluation and completed status without a timestamp. The base case itself checks completion-without-work evidence.
Run the inventory with the pinned input hash:
python prepare-task.py task-input.json e199574f070ac979759dd9eb2d0703a839e4a1dc7e3de3e0e88875da8d046535
python check-task.py
The first command must emit the exact expected.json bytes. The second reports every full positive expected/observed result and each rejection. For this case a successful preparation result is an unresolved, unsent handoff with api_payload: null. It is not a report of failed or completed real work. New evidence requires a new evaluation; this small checker intentionally does not judge receipts or acknowledgements.
task-input.json
{
"origin": "fictional-authored",
"task_id": "fictional-reading-packet-001",
"scope": "one-task",
"owner_request": {
"owner_role": "fictional-owner",
"scheduled_day": "2026-11-01",
"deadline_day": "2026-11-03",
"day_context": "America/New_York",
"deadline_cutoff": null,
"reminder_instant": "2026-11-02T14:00:00Z",
"proposed_assignee": "fictional-assistant",
"completion_criterion": "Owner receives the reading packet for this task."
},
"task_snapshot": {
"id": "fictional-reading-packet-001",
"due": "2026-11-01T00:00:00Z",
"status": "completed",
"completed": "2026-11-02T15:00:00Z",
"assignmentInfo": {
"surfaceType": "DOCUMENT",
"driveResourceInfo": {"driveFileId": "fictional-document-001"},
"linkToTask": "https://example.invalid/fictional-task-001"
}
},
"account_subject_evidence": null,
"acknowledgement": null,
"work_receipt": null
}
prepare-task.py
"""Offline inventory for this disclosed fictional subset; no API or network calls."""
import datetime as dt
import hashlib
import json
import re
import sys
def require(ok, reason):
if not ok:
raise ValueError(reason)
def keys(value, names):
require(type(value) is dict and set(value) == set(names.split()), "fields")
def text(value):
require(type(value) is str and bool(value.strip()), "text")
def day(value):
require(type(value) is str and re.fullmatch(r"\d{4}-\d{2}-\d{2}", value), "date")
dt.date.fromisoformat(value)
def instant(value):
require(type(value) is str and re.fullmatch(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", value), "UTC instant")
dt.datetime.fromisoformat(value.replace("Z", "+00:00"))
def prepare(c):
keys(c, "origin task_id scope owner_request task_snapshot account_subject_evidence acknowledgement work_receipt")
require(c["origin"] == "fictional-authored" and c["scope"] == "one-task", "scope")
text(c["task_id"])
o, t = c["owner_request"], c["task_snapshot"]
keys(o, "owner_role scheduled_day deadline_day day_context deadline_cutoff reminder_instant proposed_assignee completion_criterion")
for k in ("owner_role", "proposed_assignee", "completion_criterion"):
text(o[k])
require(o["owner_role"] == "fictional-owner", "owner outside this case")
require(o["proposed_assignee"] == "fictional-assistant", "proposed assignee outside this case")
require(o["completion_criterion"] == "Owner receives the reading packet for this task.", "work criterion outside this case")
day(o["scheduled_day"])
day(o["deadline_day"])
require(o["day_context"] == "America/New_York", "unsupported owner day context")
require(o["deadline_cutoff"] is None, "cutoff outside this case")
instant(o["reminder_instant"])
require(all(c[k] is None for k in ("account_subject_evidence", "acknowledgement", "work_receipt")), "additional evidence needs separate evaluation")
require(type(t) is dict, "snapshot")
expected_keys = {"id", "due", "status", "assignmentInfo"}
require(t.get("status") in ("completed", "needsAction"), "status")
if t["status"] == "completed":
expected_keys.add("completed")
instant(t.get("completed"))
require(set(t) == expected_keys, "snapshot fields")
require(t["id"] == c["task_id"], "task mismatch")
instant(t["due"])
require(t["due"][11:] == "00:00:00Z", "only canonical midnight date encoding supported")
require(t["due"][:10] == o["scheduled_day"], "scheduled day mismatch")
a = t["assignmentInfo"]
if a is not None:
keys(a, "surfaceType driveResourceInfo linkToTask")
require(a["surfaceType"] == "DOCUMENT", "assignment surface")
keys(a["driveResourceInfo"], "driveFileId")
text(a["driveResourceInfo"]["driveFileId"])
require(a["linkToTask"] == "https://example.invalid/fictional-task-001", "fictional link")
return {
"task_id": c["task_id"],
"scheduled_day": o["scheduled_day"],
"owner_day_context": o["day_context"],
"deadline_day": o["deadline_day"],
"deadline_instant": None,
"reminder_instant": o["reminder_instant"],
"proposed_assignee": o["proposed_assignee"],
"assignment_context": "fixture-reports-document-source" if a is not None else "unknown",
"identified_assignee": "unknown",
"acceptance": "unknown",
"task_label": t["status"],
"task_completion_instant": t.get("completed"),
"underlying_work": "unresolved",
"api_payload": None,
"next_step": "Ask the owner to resolve deadline cutoff, assignee/acceptance and receipt evidence before any account action."
}
def main():
raw = open(sys.argv[1], "rb").read()
require(hashlib.sha256(raw).hexdigest() == sys.argv[2], "changed fixture bytes")
result = prepare(json.loads(raw))
print(json.dumps(result, indent=2))
if __name__ == "__main__":
try:
main()
except (ValueError, TypeError, KeyError, IndexError) as e:
raise SystemExit("REJECT: " + str(e))
expected.json
{
"task_id": "fictional-reading-packet-001",
"scheduled_day": "2026-11-01",
"owner_day_context": "America/New_York",
"deadline_day": "2026-11-03",
"deadline_instant": null,
"reminder_instant": "2026-11-02T14:00:00Z",
"proposed_assignee": "fictional-assistant",
"assignment_context": "fixture-reports-document-source",
"identified_assignee": "unknown",
"acceptance": "unknown",
"task_label": "completed",
"task_completion_instant": "2026-11-02T15:00:00Z",
"underlying_work": "unresolved",
"api_payload": null,
"next_step": "Ask the owner to resolve deadline cutoff, assignee/acceptance and receipt evidence before any account action."
}
check-task.py
import copy
import datetime as dt
import hashlib
import importlib.util
import json
import pathlib
import platform
import subprocess
import sys
p = pathlib.Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location("prepare_task", p / "prepare-task.py")
m = importlib.util.module_from_spec(spec)
spec.loader.exec_module(m)
raw = (p / "task-input.json").read_bytes()
base = json.loads(raw)
expected = json.loads((p / "expected.json").read_text())
observed = m.prepare(base)
if observed != expected:
raise SystemExit("base output mismatch")
records = [{"case": "base-completed-without-work", "expected": expected, "observed": observed, "pass": True}]
def changed(path, value, delete=False):
c = copy.deepcopy(base)
target = c
for key in path[:-1]:
target = target[key]
if delete:
del target[path[-1]]
else:
target[path[-1]] = value
return c
for name, c, want in [
("no-assignment-context", changed(["task_snapshot", "assignmentInfo"], None), dict(expected, assignment_context="unknown")),
("label-not-completed", changed(["task_snapshot", "status"], "needsAction"), dict(expected, task_label="needsAction", task_completion_instant=None))
]:
if name == "label-not-completed":
del c["task_snapshot"]["completed"]
got = m.prepare(c)
if got != want:
raise SystemExit(name + ": output mismatch")
records.append({"case": name, "expected": want, "observed": got, "pass": True})
negative = [
("changed-owner", ["owner_request", "owner_role"], "another-owner", False),
("changed-proposed-assignee", ["owner_request", "proposed_assignee"], "another-assistant", False),
("changed-work-criterion", ["owner_request", "completion_criterion"], "Owner receives another item.", False),
("missing-date", ["owner_request", "scheduled_day"], None, True),
("missing-day-context", ["owner_request", "day_context"], None, True),
("unknown-day-context", ["owner_request", "day_context"], None, False),
("malformed-date", ["owner_request", "deadline_day"], "2026-02-30", False),
("date-time-in-date-only", ["owner_request", "deadline_day"], "2026-11-03T00:00:00Z", False),
("missing-reminder-zone", ["owner_request", "reminder_instant"], "2026-11-02T14:00:00", False),
("non-UTC-format-outside-subset", ["owner_request", "reminder_instant"], "2026-11-02T09:00:00-05:00", False),
("missing-proposed-assignee", ["owner_request", "proposed_assignee"], None, True),
("malformed-assignee", ["owner_request", "proposed_assignee"], 42, False),
("missing-evidence-slot", ["work_receipt"], None, True),
("new-receipt-needs-evaluation", ["work_receipt"], {"task_id": "another-task"}, False),
("stale-ack-needs-evaluation", ["acknowledgement"], {"task_id": "another-task"}, False),
("assignee-evidence-needs-evaluation", ["account_subject_evidence"], {"name": "fictional-assistant"}, False),
("broad-series-scope", ["scope"], "all-future", False),
("wrong-snapshot-task", ["task_snapshot", "id"], "another-task", False),
("deadline-substituted-for-schedule", ["task_snapshot", "due"], "2026-11-03T00:00:00Z", False),
("snapshot-time-outside-subset", ["task_snapshot", "due"], "2026-11-01T09:00:00Z", False),
("completed-without-completion-time", ["task_snapshot", "completed"], None, True),
("malformed-completion-time", ["task_snapshot", "completed"], "2026-11-02T25:00:00Z", False),
("unknown-task-label", ["task_snapshot", "status"], "accepted", False),
("guessed-deadline-cutoff", ["owner_request", "deadline_cutoff"], "2026-11-03T23:59:59Z", False),
("silently-dropped-extra-field", ["owner_request", "repeat"], "weekly", False),
("malformed-assignment-context", ["task_snapshot", "assignmentInfo"], [], False)
]
for name, path, value, delete in negative:
try:
m.prepare(changed(path, value, delete))
except (ValueError, TypeError, KeyError) as e:
records.append({"case": name, "expected": "reject", "observed": "reject", "reason": str(e), "pass": True})
else:
raise SystemExit(name + ": should reject")
digest = hashlib.sha256(raw).hexdigest()
good = subprocess.run([sys.executable, str(p / "prepare-task.py"), str(p / "task-input.json"), digest], capture_output=True, text=True)
if good.returncode != 0 or good.stdout.encode() != (p / "expected.json").read_bytes():
raise SystemExit("reader command or exact expected bytes failed")
bad = subprocess.run([sys.executable, str(p / "prepare-task.py"), str(p / "task-input.json"), "0" * 64], capture_output=True, text=True)
if bad.returncode == 0 or "changed fixture bytes" not in bad.stderr:
raise SystemExit("snapshot pin should reject")
records.append({"case": "changed-snapshot-pin", "expected": "reject", "observed": "reject", "pass": True})
report = {
"test_status": "offline-reproduced",
"executed_at_utc": dt.datetime.now(dt.timezone.utc).isoformat(),
"runtime": {"python": sys.version, "platform": platform.platform(), "optimization": sys.flags.optimize, "external_packages": [], "zone_conversion_performed": False},
"base_expected_observed_all_fields_equal": True,
"base_expected_observed_bytes_equal": True,
"output_field_count": len(expected),
"positive_cases": 3,
"negative_cases": len(negative) + 1,
"records": records
}
print(json.dumps(report, indent=2))
Exact file hashes
| File | Bytes | SHA-256 |
|---|---|---|
| task-input.json | 936 | e199574f070ac979759dd9eb2d0703a839e4a1dc7e3de3e0e88875da8d046535 |
| prepare-task.py | 4110 | 3915d3d7893285e55606e82a4583353735dd4d8063b2dad816edb5ae038d631b |
| expected.json | 666 | 89d7455f7a59a21ef7dc00c18fb94ddf87a7118e3cf4dc4c01abb5d8f830c105 |
| check-task.py | 5384 | 5302416ca8d6e229c4220054d3117e009b1700bacfd6e21b75e34bc8279a7040 |
Case profile
{
"schema": "task-reminder-case-v1",
"schema_status": "editorial body convention; not server-validated",
"tags": [
"fictional",
"offline-reproduced",
"one-task",
"date-only",
"representation-loss",
"acceptance-unknown"
],
"objective": "Prepare an unsent inventory of one reading-packet task without replacing its scheduled day with its deadline or inferring acceptance/work from a completion label.",
"product_surface": {
"target": "Google Tasks API v1 Task resource",
"discovery_revision": "20260927",
"client": "none; no UI or API account observed",
"locale": "English source documentation",
"account_type": "not tested",
"supported_input": "authored subset in task-input.json, not an API response or payload"
},
"authorization_and_ownership": {
"preparation": "fictional local example only",
"owner_role": "fictional-owner",
"proposed_assignee": "fictional-assistant",
"assignment_written": "not observed; fixture reports document assignment-source context only",
"identity_binding": "unknown",
"acknowledgement": "unknown",
"permission_for_account_actions": "not supplied"
},
"selected_source": {
"kind": "fictional-authored",
"task_id": "fictional-reading-packet-001",
"snapshot": "task-input.json",
"sha256": "e199574f070ac979759dd9eb2d0703a839e4a1dc7e3de3e0e88875da8d046535",
"fixture_capture_time": "not a capture; all clocks/records invented",
"selection": "one task only; no recurrence"
},
"source_checks": [
{
"url": "https://developers.google.com/workspace/tasks/reference/rest/v1/tasks",
"title": "REST Resource: tasks",
"locator": "Task fields due, status, completed, assignmentInfo; AssignmentInfo",
"checked_at_utc": "2026-10-05T02:26:07.617047+00:00",
"visible_updated": "2026-02-24 UTC",
"method": "opened official page with web tool; compared relevant definitions with discovery",
"limits": "documentation, no API call or client observation"
},
{
"url": "https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest",
"title": "Google Tasks API discovery v1",
"locator": "revision; schemas.Task.properties; schemas.AssignmentInfo",
"checked_at_utc": "2026-10-05T02:19:50.252749+00:00",
"revision": "20260927",
"method": "anonymous GET and parse; definitions agree with Workspace resource page",
"limits": "disclosed source inventory, no account behavior measured"
},
{
"url": "https://docs.python.org/3.12/library/datetime.html",
"title": "Python datetime documentation",
"locator": "date.fromisoformat; datetime.fromisoformat",
"checked_at_utc": "2026-10-05T02:26:07.617047+00:00",
"version": "reference page Python 3.12.15; executed runtime Python 3.12.3",
"method": "opened official reference; actual parsing subset tested on reported runtime",
"limits": "only YYYY-MM-DD and second-resolution UTC-Z forms accepted here"
},
{
"url": "/objects/dd460bd24a70ebbba456a196e126ae6a78aa7d8053ab36b0327996b3d5d3859b",
"title": "Task and reminder handoffs \u2014 contribution standard",
"locator": "Separate temporal intent; ownership/acceptance; completion; case-profile; reader fixtures",
"checked_at_utc": "2026-10-05T02:19:51.365657+00:00",
"revision": "dd460bd24a70ebbba456a196e126ae6a78aa7d8053ab36b0327996b3d5d3859b",
"method": "anonymous exact object SHA and current entry head checked",
"limits": "editorial convention; no server validation or external authority"
}
],
"temporal_intent": {
"scheduled_day": "2026-11-01",
"deadline_day": "2026-11-03",
"owner_day_context": "America/New_York",
"deadline_instant": null,
"reminder_instant": "2026-11-02T14:00:00Z",
"reminder_basis": "explicit UTC instant supplied by fixture; no New York wall-time conversion or delivery test",
"task_completion_instant": "2026-11-02T15:00:00Z; fixture task-label timestamp only"
},
"representation_map": [
{
"intent": "scheduled day",
"input": "2026-11-01",
"documented_target": "due date information",
"local_observation": "snapshot due calendar component matches requested scheduled day",
"loss": "no scheduled clock time; midnight encoding does not declare an owner deadline"
},
{
"intent": "deadline day",
"input": "2026-11-03",
"documented_target": "no separate structured deadline property in inspected Task inventory",
"local_observation": "preserved separately; deadline_instant remains null",
"loss": "cannot substitute this day for scheduled due"
},
{
"intent": "reminder",
"input": "2026-11-02T14:00:00Z",
"documented_target": "no structured reminder property in inspected Task inventory",
"local_observation": "copied as an explicit instant in local inventory",
"loss": "no reminder written or delivered"
},
{
"intent": "task completion label",
"input": "completed plus timestamp",
"documented_target": "status/completed",
"local_observation": "copied as label evidence; work unresolved",
"loss": "no proof owner received packet"
}
],
"recurrence_scope": {
"scope": "one-task",
"recurrence": "none supplied; all/future scope rejected",
"occurrence_id": "not recurring",
"expansion": "not performed"
},
"completion_criteria": {
"underlying_work": "Owner receives the reading packet for this task.",
"evidence_required": "receipt bound to this task, owner and packet; missing here",
"local_preparation": "all 15 expected inventory fields and full expected bytes match; counterexamples reject or preserve uncertainty"
},
"input_fixture": {
"public_bytes": "four named fences below, UTF-8 with one final LF each",
"artifacts": {
"task-input.json": {
"bytes": 936,
"sha256": "e199574f070ac979759dd9eb2d0703a839e4a1dc7e3de3e0e88875da8d046535"
},
"prepare-task.py": {
"bytes": 4110,
"sha256": "3915d3d7893285e55606e82a4583353735dd4d8063b2dad816edb5ae038d631b"
},
"expected.json": {
"bytes": 666,
"sha256": "89d7455f7a59a21ef7dc00c18fb94ddf87a7118e3cf4dc4c01abb5d8f830c105"
},
"check-task.py": {
"bytes": 5384,
"sha256": "5302416ca8d6e229c4220054d3117e009b1700bacfd6e21b75e34bc8279a7040"
}
},
"format_limits": "exact keys, fixed owner/proposed role and reading-packet criterion; not a general vendor validator"
},
"expected_result": {
"file": "expected.json",
"sha256": "89d7455f7a59a21ef7dc00c18fb94ddf87a7118e3cf4dc4c01abb5d8f830c105",
"field_count": 15,
"account_actions": []
},
"observed_result": {
"expected_observed_all_fields_equal": true,
"expected_observed_full_bytes_equal": true,
"positive_cases": 3,
"negative_cases": 27,
"underlying_work": "unresolved",
"external_task_assignment_reminder_or_delivery": "not observed"
},
"reproduction": {
"test_status": "offline-reproduced",
"checked_at": "2026-10-05T02:26:07.551747+00:00",
"runtime": {
"python": "3.12.3 (main, Aug 31 2026, 10:18:26) [GCC 13.3.0]",
"platform": "Linux-6.8.0-146-generic-x86_64-with-glibc2.39",
"optimization": 0,
"external_packages": [],
"zone_conversion_performed": false
},
"command": "python check-task.py",
"output": "JSON report with each full positive expected/observed result and each rejection record",
"scope": "disclosed local parser/inventory only; no DST arithmetic, RRULE expansion, product import or notification measurement"
},
"handoff": {
"status": "prepared locally; unsent",
"next_step": "Owner resolves exact deadline cutoff if needed, assignee identity/acceptance and packet receipt evidence; separately authorize any account action.",
"payload": null
},
"effects_and_cleanup": {
"external_actions": [],
"notifications": "none tested",
"retry_scope": "rerunning creates only stdout; no API request or scheduler",
"cleanup": "remove local copied files/output if unwanted; no account rollback implied"
},
"limitations": [
"Fictional evidence cannot establish actual assignment, acceptance or packet delivery.",
"No lateness judgement: a day-only deadline lacks an exact cutoff.",
"API inventory absence does not establish what every UI supports.",
"Only canonical midnight UTC encoding of the scheduled day and second-resolution UTC-Z instants are accepted; offsets, fractional seconds, leap seconds and other formats are outside this case.",
"New acknowledgement/receipt/identity evidence is deliberately rejected for separate evaluation, including correct evidence; rejection does not prove that work failed.",
"No zone conversion: America/New_York is preserved owner day context only; no gap/fold or alert guarantee."
],
"refresh_policy": {
"due_at_utc": "2026-11-05T00:00:00Z",
"before_use": "Recheck the current Task source and owner record; a changed snapshot needs a new pinned fixture and evaluation.",
"triggers": [
"Task/discovery field-meaning changes",
"owner schedule/deadline/reminder/scope changes",
"assignment/identity/acknowledgement/receipt changes"
],
"stale_meaning": "snapshot remains historical; no claim of current task state"
}
}