DEV Community

Casey Sun
Casey Sun

Posted on

Renewing a Lock Lease Is Not a Prompt Task

A billing worker woke a second replica at 02:10. Both replicas believed they held the nightly export lock. The second replica had renewed a lease it never owned.

This walkthrough uses a constructed billing export incident. No customer metric, vendor quota, or outage duration is claimed here. The failure mode remains common in agent-backed workers.

How the constructed incident unfolded

First holder

The first worker acquired the export lock at 02:00. Its fencing token was an integer from the lock service. A deploy restarted that worker before the export finished.

Bad advice

The assistant read a stale timestamp from one log line. It told the new replica to renew the lease immediately. The prompt never received the current fencing token.

Resulting write

The new replica wrote a second invoice batch. Operators reversed that batch by hand later that morning. The model had treated a lock as prose.

Failure analysis

Three independent mistakes stacked in the constructed story. The assistant acted on a timestamp instead of a token. The replica accepted prose as an authorization to write.

The platform let a completion path sit beside the lock client. Removing that path leaves the lock service as sole writer.

The boundary this guide defends

Lease renewal is a fencing decision, not a completion. A fencing token must come from the lock service. A model completion must not mint that token.

Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option. Those claims are operator-supplied availability notes, not measured limits.

Current quotas, hardware, and duration belong in current product docs. This guide deliberately states none of those numbers.

A free model can draft a test or explain a log. It must not decide who holds a lease.

A free server may host only a lab harness. The operator must keep that host off production networks.

Red flags

Teams should watch for these signs before any free-lane trial. Any single sign below is already a stop condition.

  • A prompt returns renew, steal, or extend as an action.
  • The same completion selects a tenant and a lock name.
  • Lease duration arrives as model text rather than config.
  • A free server process can reach the production lock API.
  • Fencing tokens are parsed from unstructured model output.
  • Retry advice and lease advice share one prompt.
  • Operators lack a kill switch outside the model path.
  • The lab host still carries a production lock credential.

Any one of those signs is enough to stop. Combined signs mean the design is already unsafe.

What the free lane may still do

Drafting lane

The free model lane may summarize a redacted timeout log. It may draft a unit test for the deny gate. It may list unfamiliar fields in a lock response.

Isolated lab host

The free server may run that harness in isolation. Isolation is an operator duty, not a default product promise.

The lab host should have no route to the production lock API. It should also avoid any shared secret store with production.

Neither lane may choose renew, steal, or release. Neither lane may invent a fresh fencing token.

Better alternatives

The lease path should stay boring, local, and deterministic. The steps below keep renewal out of completions.

  1. A real lock service should issue every fencing token.
  2. Lease deadlines should live in that service, not in prompts.
  3. Application code should compare clocks and fencing tokens.
  4. The model should see only redacted post-incident log text.
  5. Explanatory drafts should stay on a separate free model lane.
  6. The harness should run on a free server that cannot call production.
  7. A human should merge every lease-policy change.

The model may describe a failure after the fact. The lock service still owns the next renewal.

Decision table

The table below is a policy, not a benchmark. No latency, cost, or uptime figure appears in it.

Signal in hand Owner Free model Free server
Fencing token check Lock client Deny Deny
Lease deadline math Lock client Deny Deny
Steal or renew action Lock service Deny Deny
Redacted log summary Drafting lane Allow Optional
Harness unit tests Isolated lab Draft only Allow if isolated
Production lock API Lock service Deny Deny

Isolation means no production credentials on that host. Optional means the free server is unnecessary for a pure draft.

A local deny gate

The following Python is a proposal, not a live run. It was not executed against a live lock service. It shows the shape of a local deny gate.

Shape check

from dataclasses import dataclass

ALLOWED_DRAFT_TASKS = frozenset({"explain_log", "draft_test"})
LEASE_ACTIONS = frozenset({"renew", "steal", "extend", "release"})

@dataclass(frozen=True)
class LeaseRequest:
    action: str
    fencing_token: str
    source: str

def admit_lease(req: LeaseRequest) -> bool:
    if req.source != "lock_client":
        return False
    if req.action not in LEASE_ACTIONS:
        return False
    if not req.fencing_token.isdigit():
        return False
    return True

def admit_draft(task: str, body: str) -> bool:
    if task not in ALLOWED_DRAFT_TASKS:
        return False
    lowered = body.lower()
    banned = LEASE_ACTIONS | {"fencing", "lease_until"}
    return not any(word in lowered for word in banned)
Enter fullscreen mode Exit fullscreen mode

The trusted lock client alone should call admit_lease. A draft gate should run before any free model sees text. A draft that contains renew or steal never leaves the gate.

Renewal helper

def renew_from_client(lock, token: str, now: int) -> bool:
    if lock.fencing_token != token:
        return False
    if now >= lock.lease_until:
        return False
    lock.lease_until = now + lock.lease_ttl
    return True
Enter fullscreen mode Exit fullscreen mode

This helper never reads model output or log prose. The token argument must already come from the lock service.

The lease_ttl value should come from reviewed config. It should never be parsed from a completion.

Lab commands

Operators should run these checks in a disposable lab environment. These commands should not target production hosts.

python -m pytest tests/test_lease_gate.py -q
git grep -n "renew" -- app/locks app/prompts
git grep -n "fencing_token" -- app/prompts
env | awk -F= '/LOCK|FENCING/ {print $1}'
Enter fullscreen mode Exit fullscreen mode

A prompt hit on fencing_token is a red flag. A lock-client hit on renew can be legitimate. The directory split is the actual code review.

An environment hit on a lock secret name fails the lab. The free server image should fail that same check.

Unexecuted test plan

Teams should treat this plan as unexecuted until a local run records output. That recording belongs next to the git revision.

  1. A model completion source should produce denial.
  2. An empty fencing token should produce denial.
  3. A draft that says renew the lease should produce denial.
  4. A redacted timeout summary should produce allow.
  5. The lab host should hold no production lock credentials.
  6. The free server image should lack a route to the lock API.
  7. Unknown fields in a model completion should fail closed.
  8. A paraphrased keep the hold alive draft should fail closed.

Teams should not invent pass rates before that local run. A green local run still does not prove production safety.

Exit criteria

Teams should leave the free lane when any item below becomes true. Leaving is a design change, not a prompt tweak.

  • A completion can call the lock API, even indirectly.
  • Lease duration is no longer a reviewed config value.
  • The free server shares a network with production locks.
  • More than one service trusts model text for fencing.
  • An incident review cannot name the token issuer.
  • Docs and code disagree on who may steal a lease.
  • Quotas or uptime needs exceed published free-tier terms.
  • A single prompt both drafts tests and renews leases.

Exit means moving lease control fully into the lock client. Drafting help can remain on the free model lane. The free server should keep hosting only the isolated harness.

Who should not use this approach

Teams without a lock service should not start here. Teams whose one process must both draft and renew should stop. Payment capture, inventory decrement, and mailbox migration should stay out.

Those paths need this boundary plus a named domain owner. Teams should also stop if current docs contradict the availability notes.

Availability language goes stale and must be rechecked. A code review habit does not go stale the same way.

Limitations

This gate checks request shape, not distributed correctness. Clock skew, session loss, and split brain need the lock service. A string deny list will miss some paraphrased hold requests.

Teams should pair that list with a typed action enum. Unknown fields from every model payload should be rejected. Denials should be logged without raw tenant payloads.

Free model access does not make a completion authoritative. A free server does not make a host trustworthy. Both remain optional lab tools whose limits operators must re-read.

The constructed incident is a teaching story, not a case study. No vendor benchmark is claimed for this deny gate.

Closing

Renewal, steal, and release should stay inside the lock client. A free model may explain the redacted log afterward. A free server may run only an isolated harness.

Operators should read current MonkeyCode docs before any free-lane trial. Every quota and hardware note there should be treated as time-bound.

Top comments (0)