fix(tasks): allow captured task status changes and align Upcoming #833

Closed
kayg wants to merge 0 commits from fix/tasks-backend-upcoming-status into dev
Owner

A freshly created task could not change status: tasks.create writes a quoted from backlink containing #^block, and B1's strict frontmatter planner rejected literal hashes even inside a complete JSON string. HTTP reproduction returned 400 invalid_input; the engine regression exposed Grammar. The task note id, field names and notes.get version were correct. No server/TypeScript action contract change is needed.

The strict writer now accepts complete JSON quoted strings containing hashes, with independent YAML verification. Literal comments, malformed quoting, unsupported metadata shapes and resource limits retain their existing checks. Backlinks stay byte-identical and inverse splices restore the original bytes.

Upcoming now uses When, falling back to Deadline only without When, matching the approved mockup on review/preview-2026-10-29. A past When with a future Deadline is excluded from Upcoming and remains in Today. Today's existing Deadline inclusion rule is preserved, so a future When with a past Deadline may still appear in both lists. The ADR records the approved Upcoming override.

The list and badge query use tday; the covering index follows it and the tasks index version is bumped for existing Homes. Internal date-group prefixes sort days before months in SQL and Rust, including pagination and kept rows; public day/month keys and manual ranks retain their shape.

Shared writer scope and failure checks

The change removes two pre-decode hash exclusions. Complexity stays linear in bounded metadata, with no new pass or allocation. Limits remain 8 MiB/note, 64 KiB input metadata, depth 8 and 4096 list items.

Failure Effect Detection Recovery Test
Broken quotes or trailing comment Refuse before writes JSON/grammar parser Correct source metadata Refusal and property tests
JSON/YAML disagreement Refuse before writes Independent YAML model Correct source metadata Semantic/property tests
Valid quoted backlink with hash Preserve backlink; update status and owning checkbox JSON/YAML agreement Normal executor retry Byte/inverse, engine and HTTP regressions

Validation

All commands passed on dev-01 at 4637c518a12a34fc746f3c316a7dcaf0eb9ce96b, inside the Nix shell; heavy commands used ~/bin/slot:

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -j4 -- -D warnings
  • cargo test -j4 -p calternal-notes strict_frontmatter (20 passed)
  • cargo test -j4 -p calternal-tasks (67 passed)
  • cargo test -j4 -p calternal --test notes_live created_task_status_round_trip_over_http (passed; create, done, someday, todo, owning checkbox)
  • cargo test -j4 -p calternal contract
  • cargo test -j4 -p calternal-markdown-view --test contract
  • node apps/web/scripts/action-types.mjs --check
  • cargo test --workspace -j4

The HTTP regression failed on the starting dev build and passes with the fix. Existing unsupported metadata and recurring-outcome refusals remain outside this change. No merge performed. Build artifacts from this job are removed after validation.

A freshly created task could not change status: `tasks.create` writes a quoted `from` backlink containing `#^block`, and B1's strict frontmatter planner rejected literal hashes even inside a complete JSON string. HTTP reproduction returned 400 `invalid_input`; the engine regression exposed `Grammar`. The task note id, field names and `notes.get` version were correct. No server/TypeScript action contract change is needed. The strict writer now accepts complete JSON quoted strings containing hashes, with independent YAML verification. Literal comments, malformed quoting, unsupported metadata shapes and resource limits retain their existing checks. Backlinks stay byte-identical and inverse splices restore the original bytes. Upcoming now uses When, falling back to Deadline only without When, matching the approved mockup on `review/preview-2026-10-29`. A past When with a future Deadline is excluded from Upcoming and remains in Today. Today's existing Deadline inclusion rule is preserved, so a future When with a past Deadline may still appear in both lists. The ADR records the approved Upcoming override. The list and badge query use `tday`; the covering index follows it and the tasks index version is bumped for existing Homes. Internal date-group prefixes sort days before months in SQL and Rust, including pagination and kept rows; public day/month keys and manual ranks retain their shape. ## Shared writer scope and failure checks The change removes two pre-decode hash exclusions. Complexity stays linear in bounded metadata, with no new pass or allocation. Limits remain 8 MiB/note, 64 KiB input metadata, depth 8 and 4096 list items. | Failure | Effect | Detection | Recovery | Test | |---|---|---|---|---| | Broken quotes or trailing comment | Refuse before writes | JSON/grammar parser | Correct source metadata | Refusal and property tests | | JSON/YAML disagreement | Refuse before writes | Independent YAML model | Correct source metadata | Semantic/property tests | | Valid quoted backlink with hash | Preserve backlink; update status and owning checkbox | JSON/YAML agreement | Normal executor retry | Byte/inverse, engine and HTTP regressions | ## Validation All commands passed on dev-01 at `4637c518a12a34fc746f3c316a7dcaf0eb9ce96b`, inside the Nix shell; heavy commands used `~/bin/slot`: - `cargo fmt --all -- --check` - `cargo clippy --workspace --all-targets -j4 -- -D warnings` - `cargo test -j4 -p calternal-notes strict_frontmatter` (20 passed) - `cargo test -j4 -p calternal-tasks` (67 passed) - `cargo test -j4 -p calternal --test notes_live created_task_status_round_trip_over_http` (passed; create, done, someday, todo, owning checkbox) - `cargo test -j4 -p calternal contract` - `cargo test -j4 -p calternal-markdown-view --test contract` - `node apps/web/scripts/action-types.mjs --check` - `cargo test --workspace -j4` The HTTP regression failed on the starting dev build and passes with the fix. Existing unsupported metadata and recurring-outcome refusals remain outside this change. No merge performed. Build artifacts from this job are removed after validation.
fix(tasks): match Upcoming date selection and group order to mockup
Some checks failed
CI / web (pull_request) Has been cancelled
Markdown extraction contract / markdown-native-contract (pull_request) Has been cancelled
Markdown extraction contract / markdown-editor-contract (pull_request) Has been cancelled
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
3f62ac8fd6
kayg changed title from fix(tasks): created task status and Upcoming selection/order to fix(tasks): allow captured task status changes and align Upcoming 2026-11-01 19:07:29 +00:00
Author
Owner

Independent review, round 1

Verdict: request changes (one P2). Reviewed head 4637c518a12a34fc746f3c316a7dcaf0eb9ce96b, the strict writer, the #781/#813 review history, and the approved Tasks mockup.

  • P0: none.
  • P1: none.
  • P2 — Single-quoted YAML strings containing # are refused. Failing input: from: '[Source](<Source.md#^block>)' (also from: 'A''s #^block') with status: todo, then a status update. The planner returns Grammar: scalar() only parses JSON double-quoted strings and opaque_plain() rejects quoted values. The generated backlink uses double quotes, so the reported new-task path is fixed, but this round's acceptance rule explicitly includes single-quoted scalars and doubled '' escapes. The current README documents a narrower JSON-double-quote allowlist; reconcile that contract before approval.
  • P3: none.

Differential: On dev-01, the seeded 200,000-case corpus accepted 32,493 inputs and refused 167,507. Against serde_yaml: 0 typed-value mismatches, 0 target mismatches, and 0 parser errors. Exact non-target bytes, the body comment, and inverse splices were preserved in every accepted case; none of the required refusal shapes was accepted. There were 894 full-model differences, all for opaque non-target plain scalars with trailing spaces: the writer preserves the raw lexeme (x#:bbb 77/ ), while YAML decodes x#:bbb 77/. This is the documented opaque pass-through behavior and did not affect the target value.

Upcoming checks: The backend uses When, falling back to Deadline, matching the approved mockup's dayOfTask; its private date prefixes put day groups before month groups. The changed regression covers an overdue When with a future Deadline, month grouping, pagination, and kept rows.

# Independent review, round 1 **Verdict: request changes (one P2).** Reviewed head `4637c518a12a34fc746f3c316a7dcaf0eb9ce96b`, the strict writer, the #781/#813 review history, and the approved Tasks mockup. - **P0:** none. - **P1:** none. - **P2 — Single-quoted YAML strings containing `#` are refused.** Failing input: `from: '[Source](<Source.md#^block>)'` (also `from: 'A''s #^block'`) with `status: todo`, then a status update. The planner returns `Grammar`: `scalar()` only parses JSON double-quoted strings and `opaque_plain()` rejects quoted values. The generated backlink uses double quotes, so the reported new-task path is fixed, but this round's acceptance rule explicitly includes single-quoted scalars and doubled `''` escapes. The current README documents a narrower JSON-double-quote allowlist; reconcile that contract before approval. - **P3:** none. **Differential:** On dev-01, the seeded 200,000-case corpus accepted 32,493 inputs and refused 167,507. Against `serde_yaml`: 0 typed-value mismatches, 0 target mismatches, and 0 parser errors. Exact non-target bytes, the body comment, and inverse splices were preserved in every accepted case; none of the required refusal shapes was accepted. There were 894 full-model differences, all for opaque non-target plain scalars with trailing spaces: the writer preserves the raw lexeme (`x#:bbb 77/ `), while YAML decodes `x#:bbb 77/`. This is the documented opaque pass-through behavior and did not affect the target value. **Upcoming checks:** The backend uses When, falling back to Deadline, matching the approved mockup's `dayOfTask`; its private date prefixes put day groups before month groups. The changed regression covers an overdue When with a future Deadline, month grouping, pagination, and kept rows.
Author
Owner

Orchestrator decision: ready for the next train

Round 1 (#issuecomment-73537) found no P0/P1. The 200k-case differential had 0 mismatches, 0 non-target byte changes and 0 required refusals accepted, and the Upcoming fixes match the mockup.

The one P2 is that valid single-quoted scalars containing # (incl. '' escapes) are still refused. That's the safe direction: the writer refuses and the action says to edit in source view, and nothing gets mangled. Calternal's own generated backlinks use double quotes, which work. Widening the accepted grammar again is a follow-up, done only with the same differential gate.

Ready for the next train.

## Orchestrator decision: ready for the next train Round 1 (#issuecomment-73537) found no P0/P1. The 200k-case differential had 0 mismatches, 0 non-target byte changes and 0 required refusals accepted, and the Upcoming fixes match the mockup. The one P2 is that valid **single-quoted** scalars containing `#` (incl. `''` escapes) are still refused. That's the safe direction: the writer refuses and the action says to edit in source view, and nothing gets mangled. Calternal's own generated backlinks use double quotes, which work. Widening the accepted grammar again is a follow-up, done only with the same differential gate. **Ready for the next train.**
Author
Owner

Fixture correction at ccaece3dfe: Notes derives indexed created_ms from the note’s date: field (notes/src/search.rs), not a created: property. The first fixture change used the wrong property and could still pass by random id order. It is replaced with explicit Oct 1/Oct 2 note dates and assertions on both indexed millisecond values. Product date/time/priority/created/id sorting remains unchanged, matching ADR 0066 and the tasks writes v2 plan. Formatting and the focused Upcoming test passed on dev-02 (1/1); the complete final scratch workspace run is active.

Fixture correction at ccaece3dfecbe2048634fc792d7d4a2c6e31f324: Notes derives indexed `created_ms` from the note’s `date:` field (`notes/src/search.rs`), not a `created:` property. The first fixture change used the wrong property and could still pass by random id order. It is replaced with explicit Oct 1/Oct 2 note dates and assertions on both indexed millisecond values. Product date/time/priority/created/id sorting remains unchanged, matching ADR 0066 and the tasks writes v2 plan. Formatting and the focused Upcoming test passed on dev-02 (1/1); the complete final scratch workspace run is active.
Author
Owner

BM8 validation at scratch b9dac07806a398f53f8a9acaf1506d4b6f718a30: cargo fmt --all -- --check and cargo test --workspace -j4 passed on dev-01 in the standard Nix/slot shell, 1,483 passed and 22 ignored, with no skips or test-thread override. Four report selectors passed 22/22 on Chromium/WebKit, zero retries. Final production code passed 30 fresh Chromium composer invocations (90 tests, zero retries) during one ordinary slot build. Exact commands, head provenance, append samples, retained failures and attached raw evidence: #844 (comment). No merge or train change; owned jobs finished and VM targets/temp Homes cleaned.

BM8 validation at scratch `b9dac07806a398f53f8a9acaf1506d4b6f718a30`: `cargo fmt --all -- --check` and `cargo test --workspace -j4` passed on dev-01 in the standard Nix/slot shell, 1,483 passed and 22 ignored, with no skips or test-thread override. Four report selectors passed 22/22 on Chromium/WebKit, zero retries. Final production code passed 30 fresh Chromium composer invocations (90 tests, zero retries) during one ordinary slot build. Exact commands, head provenance, append samples, retained failures and attached raw evidence: https://git.kayg.org/kayg/calternal/pulls/844#issuecomment-74911. No merge or train change; owned jobs finished and VM targets/temp Homes cleaned.
Author
Owner

Closing: head ccaece3d is already in dev (reached via 92f4727c); nothing left to merge. Branch kept.

Closing: head ccaece3d is already in dev (reached via 92f4727c); nothing left to merge. Branch kept.
kayg closed this pull request 2026-11-04 13:04:57 +00:00
Some checks failed
CI / web (pull_request) Has been cancelled
Markdown extraction contract / markdown-native-contract (pull_request) Has been cancelled
Markdown extraction contract / markdown-editor-contract (pull_request) Has been cancelled
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal!833
No description provided.