All keys, fields, and values are strings; empty strings are valid and None denotes absence. No disk, network, wall time, or threading is needed.

Prototype: implement RecordStore() with set(key, field, value) -> None, get(key, field) -> str | None, and scan(key, prefix="") -> list[tuple[str, str]]. Setting replaces an existing field. Scan includes fields starting with the case-sensitive prefix and sorts by field name. Missing records produce None or []. Returned lists are fresh snapshots; records and instances are independent.

Final: implement TemporalDatabase():

  • Every public method takes a nonnegative integer ts. Valid calls, including reads and unsuccessful conditional/deletion calls, advance the accepted time. Equal timestamps are allowed; a later call at the same timestamp wins. A smaller timestamp raises ValueError without changing history or accepted time. Booleans and noninteger arguments are outside this exercise's input domain.
  • set(ts, key, field, value, ttl=None) -> None writes a version. ttl=None means no expiration; otherwise ttl is a positive integer. A write at ts is visible on [ts, ts + ttl). Replacing a field replaces its lifetime too. A nonpositive TTL raises ValueError before any time or state change.
  • get(ts, key, field) -> str | None reads at ts.
  • delete(ts, key, field) -> bool appends a deletion marker only when the field is currently visible. Missing or expired fields return False.
  • compare_and_set(ts, key, field, expected, value, ttl=None) -> bool writes the new value and lifetime only if the current visible value equals the string expected. Missing/expired fields return False. TTL validation occurs even if comparison would fail.
  • scan(ts, key, prefix="") returns a fresh list of visible (field, value) tuples, filtered by case-sensitive prefix and sorted by field name.
  • get_at(ts, key, field, at) -> str | None reads history at integer at, where 0 <= at <= ts. Invalid at raises ValueError without advancing accepted time. Reads before creation, at/after expiration, or after a deletion return None. An expired newer version never reveals an older version. History reflects operations already processed; later same-timestamp writes become visible to later calls.

Rejected operations preserve history. All validation errors preserve accepted time as well. Separate instances share nothing. Run python main.py --stage prototype, then python main.py --stage final (the default). Edit exercise.py; leave main.py unchanged.

Drag or use the arrow keys to resize. Home collapses the question; End collapses the editor. Enter or double-click resets the split.
Loading editor…
No results yet.

Complete the starter code, then run the checks.
Results and errors will appear here.