fix: a card.json with null dates renders instead of crashing#30
Draft
ohad6k wants to merge 1 commit into
Draft
Conversation
months_between() caught (ValueError, IndexError) but not TypeError. A
reducer that writes "first_date": null instead of "" makes
stats.get("first_date", "") return None, and None[:4] raises an uncaught
TypeError that escapes both print_card() and render_card_html(), so
`emulo --card` tracebacks instead of degrading.
Adding TypeError to the except tuple returns 0, which is already the
"unknown" value here: both renderers guard the months row with `if
months:` and skip it, exactly how they treat every other missing stat.
The card renders, minus one row. Non-string dates (an epoch int, a list)
degrade the same way.
tests/test_card_null_dates.py covers months_between directly, both
renderers, and `emulo --card` end to end on a card.json with JSON nulls.
On the unfixed code those tests produce 4 errors and 1 failure; after the
fix all 8 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
The crash
emulo --cardtracebacks on acard.jsonwhose stats carry JSON nulls.months_between()inemulo.pycaught(ValueError, IndexError)but notTypeError. A reducer that writes"first_date": nullinstead of""makesstats.get("first_date", "")returnNone, andNone[:4]raises an uncaughtTypeErrorthat escapes both call sites —print_card()(emulo.py:2599) andrender_card_html()(emulo.py:2879). Neither has its own guard, so the user gets a traceback instead of a card.The fix
One line:
except (TypeError, ValueError, IndexError).Returning
0is already the "unknown" value for this field — I checked both renderers rather than inventing a new sentinel. Each guards the months row withif months:and skips it when falsy (emulo.py:2621 and emulo.py:2888), which is exactly how they treat every other missing stat (sessions,tokens,messagesare allif stats.get(...)). So a null date degrades to an omitted row, not a dash and not a bogus zero. The card renders, one row shorter. Non-string dates (an epoch int, a list) now degrade the same way instead of crashing.Diff is 1 changed line plus a 3-line comment in
months_betweenonly. No caller guard was needed — the callers already handle0correctly.Verification
New file:
tests/test_card_null_dates.py— 8 tests coveringmonths_between()directly, both renderers, andemulo --cardend to end via subprocess on acard.jsoncontaining JSON nulls.Before the fix (tests written first, run against unmodified
emulo.py):The 4 errors were the raw
TypeErrorescaping; the 1 failure was the end-to-end CLI test assertingreturncode == 0and getting1with a traceback on stderr. The 3 that passed are the controls: real dates still compute the span, empty/malformed strings already degraded viaValueError.After the fix:
Full suite:
The one remaining failure is a release pin, and I deliberately did not fix it
test_bootstrap.test_release_runtime_hashes_match_canonical_repository_bytesfails. It is not a behavior failure — it asserts that the sha256 in.agents/skills/emulo/runtime.jsonequals the canonical bytes ofemulo.py, so any change toemulo.pytrips it until the pin is regenerated.I verified this is caused solely by my edit: at
HEAD,emulo.pyhashes to22e305f9..., which is exactly the pinned value. With my change it hashes toba8cd014....Repo convention (commits
138252bb"Runtime SHA repinned",99519743) is to repin in the same commit, leavingrefat the current version. I did not do it here because that file is runtime-integrity / release plumbing and was outside the files I was scoped to touch. It is a one-line, purely derived change for whoever merges:(
refstaysv0.6.0;MINING_PROMPT.mdis untouched.) With that one line applied, the suite is 404/404 green minus the 3 pre-existing skips. Every other test in the suite passes on this branch as-is.Merge-order note: this breaks PR #28 if #28 merges second
PR #28 (
agents/tests-coverage, not merged) contains two@unittest.expectedFailuretests for exactly this bug. Once this fix lands, those two will report "unexpected success" and fail that branch.I did not touch, edit, or comment on #28. Whoever merges should either:
@unittest.expectedFailuredecorators before merging (its tests then pass for real), orOrder matters either way; the decorators have to come off.
Draft, opened unattended by an agent. Please read the release-pin section above before merging.
🤖 Generated with Claude Code