Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions docs/liskov/concepts/replacement-custody.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,17 @@ ambiguous nonzero gate into “complete.”
## Failure budgets

Launch retries are bounded by policy and surfaced through the Action Plan.
Runtime replace-after-failure is not enabled in the first public capability
set; v1 waits for scheduled end. This avoids hiding repeated spend or creating
unbounded replacement loops.
For a V5 registration that makes no signed runtime contact, Liskov may buy one
replacement for the occurrence after the verified scheduled start, the assigned
maximum start delay, and five more minutes. It does so only while other jobs
have recently made verified contact with Liskov. The original registration and
its financial closeout continue independently, and a late contact does not
erase a replacement already reserved. The absence of contact does not establish
a fault in your application or prove that the processor crashed.

Other runtime replace-after-failure behavior remains internal; v1 otherwise
waits for scheduled end. The one no-contact replacement still passes the
authored spend ceiling and launch pacing, so it may be deferred or refused.

The core distinction is simple: policy describes allowed intent; evidence
describes what actually happened.
10 changes: 10 additions & 0 deletions docs/liskov/operate/deployments-jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ Processor assignment is not runtime readiness. A registered job can still be
waiting to boot, fetch configuration, obtain required secret grants, or report
health.

For a V5 job that never makes signed runtime contact, Liskov can replace the
paid registration once its chain-verified start, assigned maximum start delay,
and five-minute grace have passed. This can create another paid job while the
first registration remains open. A recent verified contact from elsewhere in
the fleet is required; if Liskov cannot establish that its contact ingest is
working, it defers replacement and spends nothing. Coverage and Activity name
the no-contact reason and whether recovery is waiting, proceeding, or refused.
An exact processor selection with no other eligible processor can be refused
without buying a second registration.

After a job's strict reporting window closes, the timeline may say **Not billed
— no report filed**. For managed custody this means the finalized scanner proved
report absence, the charge is zero, the full reserve is released, and there is
Expand Down
1 change: 1 addition & 0 deletions docs/liskov/reference/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ This page is the availability owner. Guides contain only supported recipes.
| Cooperative cease | Release-gated v1 |
| Fixed-interval execution (Manifest V5 `execution.mode: interval`) | Release-gated v1; the schema accepts `every` and an optional `until`, but no interval run has been observed in production and Liskov does not yet launch an interval Application: it stops before any Service Credit reserve or job is created. The accepted behavior is one occurrence per boundary, no overlap, no catch-up burst after a pause or outage, and a recorded skip for a missed boundary. Cron, calendar, and local-time schedules are not v1 |
| Launch retry budget | v1; `maxRetries` 0–10, default 5 |
| V5 job with no signed first contact | v1; at most one early replacement per occurrence after the chain-verified start, its assigned maximum start delay, and five more minutes. Requires a verified fleet contact within 120 seconds; normal spend and placement limits still apply |
| Runtime replace-after-failure | Internal; v1 waits for scheduled end |

## Operation, money, and custody
Expand Down
17 changes: 17 additions & 0 deletions docs/liskov/troubleshooting/execution-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ Console labels:
Quiet is not stalled. Ended-unsettled is a remaining-charge state, not overdue
execution. Incomplete, stale, and unknown never become quiet or overdue.

## A registered V5 job never contacted Liskov

If Coverage names **No signed first contact**, check the registered start and
latest-start allowance before treating the job as late. Liskov permits one
early replacement only after that allowance and five more minutes. The
replacement is still subject to the Application's spend limit, launch pacing,
and an eligible processor. An exact selection with no alternative can refuse
the replacement before another reserve is made.

**Waiting for verified fleet contact** means Liskov cannot currently prove its
runtime-contact ingest is healthy; it defers the replacement without spending.
Refresh Coverage and Activity for the recorded recovery decision. Do not infer
that your code failed or that the processor crashed from missing contact alone.
If the deferral persists after contact resumes, collect the Application and
job identifiers for support. The first registration keeps its own scheduled
end and financial closeout even if a successor starts.

## Remaining charges are not Coverage below desired

An ended job can still have:
Expand Down
8 changes: 8 additions & 0 deletions scripts/check-liskov-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ check(!existsSync(join(root, 'static', 'examples', 'liskov')), 'superseded downl

const retirementPage = readFileSync(join(docsRoot, 'operate', 'retire.md'), 'utf8');
const capabilitiesPage = readFileSync(join(docsRoot, 'reference', 'capabilities.md'), 'utf8');
const replacementCustodyPage = readFileSync(join(docsRoot, 'concepts', 'replacement-custody.md'), 'utf8');
const executionCoveragePage = readFileSync(join(docsRoot, 'troubleshooting', 'execution-coverage.md'), 'utf8');
const githubActionsPage = readFileSync(join(docsRoot, 'build', 'github-actions.md'), 'utf8');
check(capabilitiesPage.includes('| Encrypted JavaScript payload delivery | Release-gated v1;'),
'encrypted JavaScript must preserve the separate registered V5 public-release gate');
Expand Down Expand Up @@ -1009,6 +1011,12 @@ check(
/\| Console Coverage and Executions convergence strip \| v1;/.test(capabilitiesPage),
'capability matrix omits the released Console convergence strip',
);
check(
/\| V5 job with no signed first contact \| v1; at most one early replacement per occurrence/.test(capabilitiesPage)
&& /assigned\s+maximum start delay, and five more minutes/.test(replacementCustodyPage)
&& /Waiting for verified fleet contact/.test(executionCoveragePage),
'public V5 first-contact recovery boundary or customer explanation is missing',
);
check(
/\| CLI execution-convergence sibling on `application execution show` \| Release-gated v1;/.test(capabilitiesPage),
'capability matrix does not gate the unreleased CLI convergence sibling',
Expand Down