feat(web): expose validity in ChunkOut + render badge in viewer (Goal 7)#540
Merged
feat(web): expose validity in ChunkOut + render badge in viewer (Goal 7)#540
Conversation
5d858bd to
3e26a7c
Compare
…r (Goal 7)
Final RFC §CLI/Web UI surface — the temporal-validity window is now
visible end-to-end. Backend exposure on ``ChunkOut`` (used by every
chunk-shaped route response: list, get, search results, similar)
threads ``valid_from_unix`` / ``valid_to_unix`` from chunk metadata.
Frontend renders a compact ``Valid: 2025-08-15 → 2026-03-31`` badge
next to the existing created-time badge in the detail modal and inside
each search result item. Always-valid chunks (both bounds null) hide
the badge entirely so the default UI stays compact for users who
haven't opted into temporal-validity frontmatter.
Expired chunks (``now > valid_to``) get a muted opacity + line-through
on the badge text, with a localized "Expired" tooltip. The chunk stays
visible — validity is a search-time filter concept (Goal 4 stage), not
a storage-level hide. The Web UI is a viewer; filtering happens
upstream when the user issues a search with ``as_of``.
Date display uses ``YYYY-MM-DD`` regardless of the original frontmatter
shape (date vs quarter), since the unix-second column does not preserve
that distinction. ``∞`` renders for unbounded sides — half-bounded
windows (only ``valid_from`` or only ``valid_to`` set) are first-class.
Drive-by fix in ``PATCH /chunks/{id}/tags``: the route reconstructed
``ChunkMetadata`` with an explicit eight-field list, silently dropping
any field not enumerated. Goal 7 adds two more such fields, so the
implicit-loss bug would have ridden along with this PR — switched to
the dict-spread copy-with-override pattern that the ``mm add`` CLI
already uses (memory.py). This also implicitly restores
``overlap_before/after``, ``parent_context``, ``file_context``, and
``language`` round-tripping through tag updates — those have been
silently lost since the route was written. Test pins the regression so
re-flattening is loud.
i18n: two new keys (``search.detail_validity_label``,
``search.detail_validity_expired``) added to en.json + ko.json
("Valid"/"유효", "Expired"/"만료됨") so the trust-UX surface stays
localized. Date format itself is locale-independent (ISO-8601 strict).
Tests (3 new, in test_web_routes.py at TestChunkValidityFields):
- ``test_chunkout_includes_validity_when_set``: chunk with both bounds
populated (2024-12-15 → 2025-Q1 end) round-trips through
``GET /api/chunks/{id}`` with the unix integers intact.
- ``test_chunkout_validity_null_when_unset``: default ``_make_test_chunk``
produces a chunk without validity → both fields serialize as ``null``
so the frontend always-valid branch (hidden badge) fires.
- ``test_tag_update_preserves_validity``: regression for the
drive-by fix — PATCH /chunks/{id}/tags must not drop validity (or
``parent_context`` / ``overlap_before`` for that matter). Inspects
the ``upsert_chunks`` await args directly because that is the wire
the silently-dropped fields would have been lost on.
Frontend rendering coverage is manual (no JS test harness in this repo);
the API contract test pins what the frontend reads from JSON.
This is the last code Goal in the RFC — no further surface work
planned. Goal-by-goal status table updated in the matching
memtomem-docs commit.
Co-Authored-By: Claude <[email protected]>
ce6bed8 to
4b946a2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Final RFC §CLI/Web UI surface — temporal-validity window visible end-to-end in the Web UI.
Backend.
ChunkOutschema gainsvalid_from_unix/valid_to_unix(both nullable, defaultNone).chunk_to_outpropagates fromChunkMetadata. Every chunk-shaped route response (list, get, search, similar) now carries the window.Frontend. Compact
Valid: 2025-08-15 → 2026-03-31badge next to the existing created-time badge in the detail modal AND inside each search result item. Always-valid chunks (both boundsnull) hide the badge entirely so the default UI stays compact for users without temporal-validity frontmatter.Expired chunks (
now > valid_to) get a muted opacity + line-through with a localized "Expired" tooltip. The chunk stays visible — validity is a search-time filter (Goal 4 stage), not a storage hide. The Web UI is a viewer; filtering happens upstream when the user issuesmem_search/mm searchwithas_of.i18n: two new keys (
search.detail_validity_label"Valid"/"유효",search.detail_validity_expired"Expired"/"만료됨") in en + ko locale JSON. Date format itself is locale-independent (ISO-8601).Drive-by fix
PATCH /api/chunks/{id}/tagsreconstructedChunkMetadatawith an explicit eight-field list, silently dropping any field not enumerated. Goal 7 adds two more such fields (valid_from_unix,valid_to_unix), so the implicit-loss bug would have ridden along with this PR. Switched to the dict-spread copy-with-override pattern thatmm addalready uses (memory.py).This also restores round-tripping for
overlap_before/after,parent_context,file_context,language— silently lost on tag updates since the route was written. Test pins the regression so re-flattening is loud (test_tag_update_preserves_validityinspects theupsert_chunksawait args directly because that's the wire the lost fields would have been dropped on).Stack
This is the last of three stacked PRs implementing Goals 5+6+7:
mem_search(as_of=...)(base:main)After this lands, all 7 RFC goals are in main. Supersession (auto-detection /
superseded_bytraversal) is deferred to a v2 RFC per §Non-goals §2.Test plan
test_web_routes.py—TestChunkValidityFields: chunkout includes validity when set / null when unset / tag-update preserves validity (regression for the drive-by fix)mm web→ memory viewer, confirm badge renders + dates are correct + expired styling fires for pastvalid_to🤖 Generated with Claude Code