Skip to content

Planned Maintenance

Counter-driven maintenance, ranked.

The PMS produces something deceptively simple: a list of jobs with due dates. The work is interpreting that list. A vessel with 200 overdue routine jobs is in better shape than one with 5 overdue critical-machinery jobs. The pipeline scores all of that and surfaces the one number a TSI actually needs: where this vessel ranks against the rest of the fleet.

maintenance-debt indexcounter-based jobsmachinery rollupscompliance %critical sparescounter discipline

Two job types, one threshold logic

Job typeTriggerDue-date driver
Counter-basedRunning hours, generator hours, compressor cyclesH_job − H_current
Calendar-basedWall-clock interval (monthly, quarterly, annual)D_due − D_today

The pipeline handles both with the same threshold logic but reports them separately — a vessel idle in port may not be falling behind on counter-based jobs even if the calendar says otherwise.

Counter-based overdue (hours): H_current − H_job_due
Calendar-based status (days):
Δ_days ≤ 0 → Overdue
0 < Δ_days ≤ 30 → Due Soon
Δ_days > 30 → In Order

The four major-machinery rollups

The PMS surveillance produces four major-machinery rollups — each computed identically but on a different equipment family:

Main Engine — the most expensive equipment to defer. Delayed cylinder overhauls show up as cylinder asymmetry on the ME performance review before they show up as engine failure.

Auxiliary Engines — each AE reported separately. When one is in maintenance, the redundancy tier of the rest matters — cross-reference AE performance for blackout-risk implications.

Purifiers — fuel and lube-oil purifiers accumulate counter hours fast. A neglected purifier is the most common upstream cause of cat-fine ingress and lube-oil contamination.

Compressors — air compressors drive emergency starts, pneumatic systems, and air-driven safety equipment. PMS lapses tend to be invisible until something fails to start.

Each rollup produces the same output shape:

CodeTitleEquipmentDue HoursCurrent HoursOverdue Hours
ME-CYL-OHCylinder overhaulME Cyl 524,00024,820820
ME-FUEL-INJFuel injector replacementME Cyl 38,0008,180180
ME-TC-WASHTurbocharger water-washME T/C1,5001,420

The maintenance-debt index

Every vessel gets a single composite score that ranks it against the fleet:

Debt index = 5 × N_critical + 2 × N_major + 1 × N_routine + 3 × N_chronic

N_chronic = jobs overdue for 3+ consecutive periods, with a +3 multiplier.

Index deltaWhat it means
FallingClosure rate exceeds arrival rate — vessel is recovering
StableSteady state
RisingDrift — the gap compounds over time

Two weeks of “rising” is enough to escalate even if the absolute index is below the fleet median. Direction matters as much as magnitude.

Fleet snapshot — weekly run

A weekly run across a 14-vessel fleet:

VesselCompliance %Debt indexTrendCritical openVerdict
POSUN96.4%311OK
AQUILA91.2%673Monitor
OCEAN88.7%1246Escalate
NEXUS94.1%220OK

OCEAN is the first action: falling compliance, rising debt index, six critical jobs open. AQUILA is the borderline case for next-week revisit. The pipeline routes OCEAN to TSI automatically.

Under the hood

Compliance percentage — the headline metric
Compliance % = N_jobs_completed_on_schedule / N_mandatory_jobs_in_period × 100

Below 90% is flagged. Below 80% triggers escalation regardless of the criticality breakdown — at that point the maintenance system itself is the issue, not individual jobs.

Job-code links — implementation

The major-machinery rollup templates hyperlink each job code to the ERP record:

def add_jobcode_links(df):
df["jobCode"] = df.apply(
lambda x: (
f"<a href=\"{x['link']}\" target=\"_blank\">{x['jobCode']}</a>"
if pd.notna(x["link"]) and x["link"] != ""
else x["jobCode"]
),
axis=1,
)
return df
def filter_and_rename_columns(df):
df = df[["jobCode", "jobTitle", "component",
"jobDueCounter", "currentCounter", "overdue", "imo"]].rename(
columns={
"jobCode": "Code", "jobTitle": "Title", "component": "Equipment",
"jobDueCounter": "Due Hours", "currentCounter": "Current Hours",
"overdue": "Overdue Hours",
}
)
return df
PMS Summary — five compliance views in one document

Beyond the machinery rollups, the PMS Summary template assembles five compliance views:

  1. Maintenance jobs — open and overdue jobs by criticality and machinery family.
  2. Certificates — expired or about-to-expire certificates, cross-referenced with the class pipeline so a class-certificate gap and a PMS gap appear in the same brief.
  3. Critical spares — spares marked critical with current quantity below minimum level. A critical-spares stockout is a future maintenance overrun the vessel doesn’t know about yet.
  4. Machinery defects — open defects on main and auxiliary engine families, cross-referenced with the defects pipeline for severity and age.
  5. Counter updation — whether the vessel has been updating engine counters at the expected cadence. Stale counters make the entire counter-based PMS view unreliable — itself a compliance issue.

A reviewer reading the Summary sees all five at once. The Summary is graded on the worst of the five, not the average.

Escalation triggers
TriggerSeverity
Any CRITICAL job overdueCRITICAL
Compliance below 80%HIGH
Chronic overrun (3+ periods) on any safety-critical jobCRITICAL
Equipment cluster (3+ jobs on same major-machinery family)HIGH
Class item overdue past deadlineCRITICAL
Counter updation lapse (stale counters > 14 days)HIGH
Data sources
SourceWhat it provides
Vessel ERP (PMS module)Job register, due dates, completion records, criticality tags
Engine running-hours feedCounter readings — drives counter-based job due dates
PMS counter forms (vessel-side)Manual counter updates when telemetry is unavailable
Critical spares inventory (ERP)Stock vs minimum levels

PMS data lives entirely in the ERP. The pipeline reads job records and reconciles counter freshness against engine running-hours from the noon-report stream — discrepancies surface as counter-updation gaps.