T-954I-lease-payload-adds-ttl-seconds
Status: closed/superseded · Impact: medium · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
The heartbeat-floor enforcement in the lease library currently
approximates the prior-heartbeat timestamp as expires_at - new_ttl
because the lease payload doesn’t carry the TTL that was originally
chosen. That approximation is correct in single-TTL operation but
wrong any time the operator (or skill) changes TTL between
heartbeats, and it also produces the awkward “first heartbeat after
claim always trips the floor” behavior documented in
T-QC31-add-sdlc-lease-cli-commands’s CLI README. Adding
ttl_seconds to the lease payload schema removes the approximation
and lets the library compute the floor exactly.
| Location | Role today |
|---|---|
plugin/lib/lease/schemas/lease.schema.json (best guess — exact path established by T-S0PK-add-lease-protocol-library-and-schemas) | Defines the lease.json payload shape. Carries expires_at, lease_id, lease_token, owner, phase, etc. — but not the TTL that produced expires_at. |
plugin/lib/lease/primitives.py (best guess) | Heartbeat enforcement reconstructs prior heartbeat as expires_at − new_ttl because ttl_seconds is not on the payload. |
plugin/scripts/lease_cli/heartbeat.py (best guess) | Surfaces the floor error to operators; README documents the “first heartbeat after claim trips floor” behavior as a known v1 quirk. |
Proposed
Section titled “Proposed”- Add
ttl_seconds: intas a required field on the lease payload schema (bump the schema version perplugin/conventions/schema-bump-checklist.md). - Update the library’s claim/transition primitives to write
ttl_secondswhenever they setexpires_at. The two values are always set together so the invariant is “ifexpires_atchanges,ttl_secondsis rewritten.” - Update the heartbeat-floor logic in the library to compute the
prior heartbeat from the payload’s stored
ttl_secondsrather than the new TTL being requested. Document the floor as(now − last_heartbeat) < ttl_seconds / 4. - Update the CLI’s heartbeat README section to remove the “first heartbeat after claim trips the floor” caveat once the fix lands.
Approach
Section titled “Approach”- Read the library and schema files introduced by
T-S0PK-add-lease-protocol-library-and-schemas to confirm
where
ttl_secondsshould land on the payload (root vs nested). - Add the field to the schema, bump the schema version, run the schema-bump checklist.
- Update primitives to persist
ttl_secondsalongsideexpires_at(claim + transition + heartbeat paths). - Replace the heuristic in the heartbeat floor with the precise
computation against the stored
ttl_seconds. - Update tests: at least one regression that switches TTL between heartbeats and asserts the floor is enforced against the prior TTL, not the new one.
- Update the lease-CLI README to drop the v1-quirk note.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/lib/lease/schemas/lease.schema.json | modify | Add ttl_seconds as a required integer field; bump schema version. Best guess; path established by T-S0PK-add-lease-protocol-library-and-schemas. |
plugin/lib/lease/primitives.py | modify | Persist ttl_seconds on every claim / transition / heartbeat; use stored value for floor computation. |
plugin/lib/lease/tests/test_heartbeat.py | modify | Add a TTL-change-between-heartbeats regression. |
plugin/scripts/lease_cli/README.md | modify | Drop the “first heartbeat after claim trips the floor” caveat once the fix lands. |
plugin/lib/lease/README.md | modify | Document the ttl_seconds field and the precise floor formula. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: The lease payload schema requires
ttl_secondsas a positive integer; existing fixtures fail validation until updated and the schema version is bumped per the bump checklist. - AC-2: A claim followed by a TTL-change heartbeat (e.g. claim
with TTL 600, heartbeat with TTL 60) enforces the floor
against the original TTL — the heartbeat at
now + smallis accepted iff(now − prior_heartbeat) >= 600/4, not>= 60/4. - AC-3: The lease-CLI README no longer documents “first heartbeat after claim trips the floor” as a known quirk; the heartbeat section reads cleanly without that caveat.
- AC-4: All existing lease library / CLI tests pass under the new schema (no payloads break silently).
Out of scope
Section titled “Out of scope”- Adding a CLI flag to override the stored
ttl_secondson heartbeat. The payload is the source of truth; operators who want to change TTL run atransition(which rewrites bothexpires_atandttl_seconds). - Migrating any in-flight lease refs that were written before this schema bump. Slice 1 has no live deployment; no data migration needed.
Dependencies
Section titled “Dependencies”- T-S0PK-add-lease-protocol-library-and-schemas — the schema this task edits is introduced there.
- T-QC31-add-sdlc-lease-cli-commands — the CLI README this task simplifies is introduced there.
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-QC31-add-sdlc-lease-cli-commands on 2026-05-23.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: Heartbeat floor needs ttl_seconds in payload for full correctness. The CLI doesn’t know a lease’s original TTL — only the new TTL being requested. Implemented ‘prior heartbeat at expires_at
- new_ttl’ as a heuristic. A clean fix would add ttl_seconds to the lease payload schema. Out of slice 1 scope; documented in the CLI README’s heartbeat section. Keywords searched: ttl_seconds, correctness, implemented, expires_at, documented, heartbeat, requested, heuristic Excluded: 2026-05-23-add-sdlc-lease-cli-commands Top candidates (score / status / headline):
- 10 / closed/done / 2026-05-21-skill-md-runtime-drift-audit — Audit /sdlc:task-work SKILL.md against per-project runtime conventions
- 10 / in-progress / 2026-05-23-add-lease-protocol-library-and-schemas — Add lease-protocol library and payload schemas
- 6 / closed/done / 2026-05-19-implement-entities-migrate — Implement /sdlc:entities-migrate to apply mechanical schema-drift fixes
- 6 / planning/backlog / 2026-05-21-task-define-prompts-for-executable-shadow — task-define prompts for executable-shadow when AC asserts live SKILL.md behavior
- 4 / closed/done / 2026-05-19-task-work-uses-per-project-quality-checks — Make /sdlc:task-work quality-check commands per-project configurable Decision: SPAWNED