An end that names a period prints as the period after it

Open
#994 11 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
62/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
postgresql, rust
Domain
backend, databases

Research direction

Start from graph::insert_fact_on and the #975 change it revises: find the paths that close a row at closes_at, where a schema flag such as facts.end_after_period would be set. Then trace the flag through rehome_tx, graph::adopt and rewrite_end_tx, the way end_derived and corrected_ends are already carried, and read time_text's module doc, which asks its printers and the web copies (fmtInterval, fmtTime, history/document/pending views) to agree. Done means every reader steps the stored end back one unit when the flag is set, the export writes validThrough "2024", and the correction route applies the write path's period rule instead of returning interval_inverted.

Written by the indexing model from the issue text.

Description

bug

Raised in the #975 review.

What happens

Since #975, an end that names a period can close an open state row that starts inside that period. The row is closed at the end of the period (graph::insert_fact_on, 0053 revised 2026-09-27).

"Works for Meridian from 2024-03-01", then "left in 2024", is stored as 2024-03-01 → 2025-01-01 at year precision. On the world axis that is right: the person worked there through 2024 and not in 2025.

Every reader prints the stored end at its precision, and that names the next period:

  • time_text::span (chat and MCP) prints 2024-03-01 → 2025. The chat prompt says 2023 means the year, so the model reads "left in 2025".
  • The graph page (fmtInterval) prints 2024-03-01 ~ 2025. The entity history, the document viewer and pending facts print the month, 2025-01.
  • The export writes schema:validThrough "2025"^^xsd:gYear.
  • The correction dialog pre-fills the end with 2025.

The same happens at every precision:

  • A row from 2023-06-01 that "left on 2023-06-01" closes at the end of that day and prints 2023-06-01 → 2023-06-02.
  • "Left in March 2024" on a row from 2024-03-10 prints 2024-03-10 → 2024-04.

The printed end is ambiguous:

  • "Left in 2025" on a row from 2020 is stored at the start of its period, 2025-01-01, and also prints → 2025.
  • A statement "from 2024-03-01 until 2025" is stored with the same values as the "left in 2024" row.

Nothing on the row tells these apart.

What I think is right

Keep the stored instant. The world axis, the timeline and the stored interval are right as they are.

Record which kind of end it is. Add a flag on the fact, for example facts.end_after_period. It says the end is the instant after the period the text named.

  • The paths in insert_fact_on that close a row at closes_at set it when that instant is the end of the period.
  • It lives with the end, as end_derived and the end's mark in corrected_ends do:
    • rehome_tx and graph::adopt carry it;
    • rewrite_end_tx drops it when it writes a new end.

Print the period the text named. That is the stored end minus one unit at its precision: 2024-03-01 → 2024 and 2023-06-01 → 2023-06-01. It is the same form as "left in 2024" on a row that began before 2024.

  • time_text::span steps back one unit when the flag is set; world stays as it is.
  • The web's printers and the export's world_time read the same flag. That covers fmtTime and the month the history, document and pending views print. time_text's module doc asks these copies to agree.
  • The export would then write validThrough "2024"^^xsd:gYear.

The correction dialog and route.

  • If the dialog showed 2024, saving it unchanged would be refused as interval_inverted: 2024-01-01 is before 2024-03-01.
  • So the correction route should take the write path's rule. An end whose period contains the row's start closes at the end of that period, with the flag set.
  • A person who types "2024" for a row from 2024-03-01 then gets what they meant, rather than an error.

Considered and not proposed

  • Store the start of the period (2024-01-01) and have readers add the period. Every reader of valid_to would change: the world-axis queries, the timeline and every printer. The row would also store an end before its start.
  • Infer it from the values, as an end whose previous period contains the start. "From 2024-03-01 until 2025" has the same values and means 2025.
  • Leave such an end unmaterialized. The open row would keep running, which the #975 review asked to avoid.

I'm raising this rather than claiming it, and am glad to implement it if the direction is right.

Dominant language
Rust
Stars
8.1k
Forks
1.1k
Avg merge
22h 14m
Merged PRs (30d)
240

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from deeplethe/utopia

All issues in deeplethe/utopia

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.