Verified against origin/development @ eb75c782dae40a6c5aa59c1d2288d60994adfa0d. Every claim below was read from that ref, not from a working tree.
Two types named CalibrationMethod, different vocabularies
1. Slice pipeline — src/slicer/Farm.Slicer.Module/Models/CalibrationMethod.cs (7 members, what actually slices):
FlowRatePass1, FlowRatePass2, TemperatureTower, FlowRateYoloRecommended, FlowRateYoloPerfectionist, MaximumVolumetricSpeed, PressureAdvanceTower
2. Saga catalogue — src/modules/Farm.Modules.Calibration/Services/Calibration/CalibrationMethodNames.cs (12 canonical wire names, snake_case):
temperature, flow_ratio_coarse, flow_ratio_fine, flow_ratio_high_range, pressure_advance_tower, pressure_advance_line, pressure_advance_pattern, flow_verification, retraction, max_volumetric_speed, shrinkage, final_verification
The sets are not a superset/subset relationship in either direction:
- In the saga, not sliceable:
flow_ratio_high_range, pressure_advance_line, pressure_advance_pattern, flow_verification, retraction, shrinkage, final_verification
- Sliceable, no saga wire name:
FlowRateYoloRecommended, FlowRateYoloPerfectionist
They are mutually exclusive by explicit design
src/slicer/Farm.Slicer.Module.Api/Controllers/Slicing/SliceJobController.cs rejects any request that combines the two:
Calibration mode is deliberately independent of, and mutually exclusive with, the unrelated printer/toolhead calibration-projects saga (issue #1940 epic). […] Reject the request outright rather than silently dropping one.
returning calibration_mode_conflicts_with_saga_ids when CalibrationProjectId, CalibrationAttemptId, or CalibrationOrchestrationId is present.
So a calibration project created through /api/calibration-projects can never be sliced through the calibration-mode path. That is intentional — but it is not discoverable by a client.
The problem: the removal-path surface is still advertised
CalibrationMethod.cs states the saga "is being removed by a separate epic" (#1940). Meanwhile CalibrationCapabilityService.cs:63 still advertises it:
["calibrationProjects"] = "/api/calibration-projects",
CalibrationProjectsController is fully implemented (9 project actions plus attempts and photos controllers), [Authorize]-gated, and covered by integration tests. Nothing about it signals "slated for deletion, and cannot slice."
Note: an earlier characterisation of this surface as "mounted but broken" was wrong — I checked the controller and it is alive and tested. The issue is divergence and signalling, not breakage.
Why it matters now
A thin client reading routes.calibrationProjects out of capabilities has no way to learn that:
- the surface is on a removal path,
- 7 of its 12 method names cannot be executed by any slicing path, and
- using it is mutually exclusive with the calibration-mode slice pipeline that does work.
PrintFarmer Desktop already built against it and accumulated dead client code as a result — filed separately as a desktop issue.
Suggested resolution
Pick one and make it explicit:
Either way, the two catalogues should have a single documented mapping (or an explicit "no mapping exists, by design" statement) so a client can tell which methods can actually produce a slice.
Verification notes
- Route inventory extracted by parsing
[Route]/[Http*] attributes from the controller at the pinned ref.
- Method sets read from the two source files at the same ref.
- The "mutually exclusive" claim is quoted from the server's own source comment and its guard clause, not inferred.
Verified against
origin/development@eb75c782dae40a6c5aa59c1d2288d60994adfa0d. Every claim below was read from that ref, not from a working tree.Two types named
CalibrationMethod, different vocabularies1. Slice pipeline —
src/slicer/Farm.Slicer.Module/Models/CalibrationMethod.cs(7 members, what actually slices):FlowRatePass1,FlowRatePass2,TemperatureTower,FlowRateYoloRecommended,FlowRateYoloPerfectionist,MaximumVolumetricSpeed,PressureAdvanceTower2. Saga catalogue —
src/modules/Farm.Modules.Calibration/Services/Calibration/CalibrationMethodNames.cs(12 canonical wire names, snake_case):temperature,flow_ratio_coarse,flow_ratio_fine,flow_ratio_high_range,pressure_advance_tower,pressure_advance_line,pressure_advance_pattern,flow_verification,retraction,max_volumetric_speed,shrinkage,final_verificationThe sets are not a superset/subset relationship in either direction:
flow_ratio_high_range,pressure_advance_line,pressure_advance_pattern,flow_verification,retraction,shrinkage,final_verificationFlowRateYoloRecommended,FlowRateYoloPerfectionistThey are mutually exclusive by explicit design
src/slicer/Farm.Slicer.Module.Api/Controllers/Slicing/SliceJobController.csrejects any request that combines the two:returning
calibration_mode_conflicts_with_saga_idswhenCalibrationProjectId,CalibrationAttemptId, orCalibrationOrchestrationIdis present.So a calibration project created through
/api/calibration-projectscan never be sliced through the calibration-mode path. That is intentional — but it is not discoverable by a client.The problem: the removal-path surface is still advertised
CalibrationMethod.csstates the saga "is being removed by a separate epic" (#1940). MeanwhileCalibrationCapabilityService.cs:63still advertises it:CalibrationProjectsControlleris fully implemented (9 project actions plus attempts and photos controllers),[Authorize]-gated, and covered by integration tests. Nothing about it signals "slated for deletion, and cannot slice."Note: an earlier characterisation of this surface as "mounted but broken" was wrong — I checked the controller and it is alive and tested. The issue is divergence and signalling, not breakage.
Why it matters now
A thin client reading
routes.calibrationProjectsout of capabilities has no way to learn that:PrintFarmer Desktop already built against it and accumulated dead client code as a result — filed separately as a desktop issue.
Suggested resolution
Pick one and make it explicit:
calibrationProjects), and give Path D: Delete printer-calibration layer, retain and reshape aggregate for server-orchestrated filament calibration #1940 a completion path.docs/API.mdwith the executable/non-executable method sets named.Either way, the two catalogues should have a single documented mapping (or an explicit "no mapping exists, by design" statement) so a client can tell which methods can actually produce a slice.
Verification notes
[Route]/[Http*]attributes from the controller at the pinned ref.