mirror of
https://github.com/callumalpass/tasknotes.git
synced 2026-07-22 12:50:26 +00:00
feat: add time-of-day component to urgencyScore formula
This commit is contained in:
parent
35dba2b974
commit
5593582bf8
4 changed files with 45 additions and 4 deletions
|
|
@ -29,6 +29,8 @@ Example:
|
|||
- Enabled lint checks that mirror Obsidian community plugin review findings, including dynamic code execution, Promise handling, deprecated APIs, unsafe stringification, directive comments, Node built-in imports, and explicit `any` usage.
|
||||
- Clarified privacy documentation for optional integrations that make periodic background network refreshes.
|
||||
- Cleaned up internal Obsidian and Bases compatibility adapters used by search and grouped views.
|
||||
- Updated default Base urgency scoring so timed tasks earlier in the day sort above later tasks with the same priority and date.
|
||||
- Thanks to @loukandr for the contribution.
|
||||
|
||||
## Fixed
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ These formulas work with either due date or scheduled date, useful for finding t
|
|||
| Formula | Description | Expression |
|
||||
|---------|-------------|------------|
|
||||
| `priorityWeight` | Numeric weight for priority sorting (lower = higher priority) | `if(priority=="none",0,if(priority=="low",1,if(priority=="normal",2,if(priority=="high",3,999))))` |
|
||||
| `urgencyScore` | Combines priority and next date proximity (due or scheduled, higher = more urgent) | `if(!due && !scheduled, formula.priorityWeight, formula.priorityWeight + max(0, 10 - formula.daysUntilNext))` |
|
||||
| `urgencyScore` | Combines priority, next date proximity, and time-of-day (due or scheduled, higher = more urgent) | `if(!due && !scheduled, formula.priorityWeight, formula.priorityWeight + max(0, 10 - formula.daysUntilNext) + (1 - ((number(date(formula.nextDate)) / 86400000) - (number(date(formula.nextDate)) / 86400000).floor())))` |
|
||||
|
||||
### Display formulas
|
||||
|
||||
|
|
|
|||
|
|
@ -381,9 +381,10 @@ function generateAllFormulas(plugin: TaskNotesPlugin): Record<string, string> {
|
|||
|
||||
// === SORTING/SCORING FORMULAS ===
|
||||
|
||||
// Urgency score: combines priority weight and days until next date (due or scheduled)
|
||||
// Higher score = more urgent. Overdue tasks get bonus, no date gets just priority
|
||||
urgencyScore: `if(!${dueProperty} && !${scheduledProperty}, formula.priorityWeight, formula.priorityWeight + max(0, 10 - formula.daysUntilNext))`,
|
||||
// Urgency score: combines priority weight, days until next date (due or scheduled), and time-of-day.
|
||||
// Higher = more urgent. The 0..1 time-of-day term ranks earlier-in-day tasks above later same-day
|
||||
// tasks at the same priority. Date-only values fall back to midnight.
|
||||
urgencyScore: `if(!${dueProperty} && !${scheduledProperty}, formula.priorityWeight, formula.priorityWeight + max(0, 10 - formula.daysUntilNext) + (1 - ((number(date(formula.nextDate)) / 86400000) - (number(date(formula.nextDate)) / 86400000).floor())))`,
|
||||
|
||||
// === DISPLAY FORMULAS ===
|
||||
|
||||
|
|
|
|||
|
|
@ -104,4 +104,42 @@ describe("defaultBasesFiles", () => {
|
|||
expect(template).not.toMatch(/date\(due\) <= today\(\) \+ "7d"/);
|
||||
expect(template).not.toMatch(/date\(scheduled\) <= today\(\) \+ "7d"/);
|
||||
});
|
||||
|
||||
it("includes a time-of-day component in urgencyScore so earlier values rank higher", () => {
|
||||
// Without the time-of-day term, two tasks at the same priority and same date but
|
||||
// different times scored identically and tie-broke on file-iteration order. The
|
||||
// 0..1 boost (1 - hourFraction(nextDate)) ranks earlier values above later ones
|
||||
// while staying smaller than the priority and days components so cross-day order
|
||||
// is preserved.
|
||||
const template = generateBasesFileTemplate("open-tasks-view", createMockPlugin() as any);
|
||||
|
||||
expect(template).toContain(
|
||||
`urgencyScore: 'if(!due && !scheduled, formula.priorityWeight, formula.priorityWeight + max(0, 10 - formula.daysUntilNext) + (1 - ((number(date(formula.nextDate)) / 86400000) - (number(date(formula.nextDate)) / 86400000).floor())))'`
|
||||
);
|
||||
|
||||
// Guard against the time-naive form returning
|
||||
expect(template).not.toMatch(
|
||||
/urgencyScore: 'if\(!due && !scheduled, formula\.priorityWeight, formula\.priorityWeight \+ max\(0, 10 - formula\.daysUntilNext\)\)'/
|
||||
);
|
||||
});
|
||||
|
||||
it("time-of-day boost is monotonic and bounded in [0, 1]", () => {
|
||||
// Verifies the math invariant the formula relies on, independent of YAML shape.
|
||||
// boost = 1 - fractional_day(ms_since_epoch). A given Date earlier in its day
|
||||
// must yield a strictly larger boost than the same date later in the day.
|
||||
const boost = (iso: string) => {
|
||||
const ms = Date.parse(iso);
|
||||
const dayMs = ms / 86_400_000;
|
||||
return 1 - (dayMs - Math.floor(dayMs));
|
||||
};
|
||||
|
||||
expect(boost("2026-04-28T00:00:00Z")).toBe(1);
|
||||
expect(boost("2026-04-28T09:00:00Z")).toBeCloseTo(0.625, 3);
|
||||
expect(boost("2026-04-28T17:00:00Z")).toBeCloseTo(0.292, 3);
|
||||
expect(boost("2026-04-28T23:59:59Z")).toBeGreaterThan(0);
|
||||
expect(boost("2026-04-28T23:59:59Z")).toBeLessThan(1 / 86_400);
|
||||
|
||||
// Monotonic: earlier in day → larger boost.
|
||||
expect(boost("2026-04-28T09:00:00Z")).toBeGreaterThan(boost("2026-04-28T17:00:00Z"));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue