Skip to content

Commit a73345e

Browse files
vupleaclaude
andcommitted
Refuse absolute-clock anchors when the backing stock read is floor-pinned
The inverted sibling of the previous commit: an entry carrying an absolute clock (no offset) derives its offset as mhz minus the stock clock at the anchor, and with no saved reference that stock source is the same possibly idle-pinned baseline read. Deriving against the pinned floor folds the pinning error into the offset - a mild target becomes a positive delta of up to the anchor's whole stock clock - and the resolved-clock bound structurally cannot catch it, because the resolved value is the entry's own (plausible) clock by construction. Where the false refusal failed loudly, this failed silently, in the overclocking direction. Only reachable with hand-written mhz-only documents (the tool's exports always carry offsets); such an anchor now refuses with a pointer at set-reference-curve, and a saved reference resolves it at any power state. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PACndXGEsXBAWWWjSvpJpW
1 parent d33e17a commit a73345e

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

‎src/TuningDocuments.cs‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,9 @@ public static bool NamesGpu(string? gpuName, string? gpuPciIds)
412412
/// document: that is the structural guard against a different card's curve. An entry without
413413
/// an offset resolves it from its absolute clock against <paramref name="stock"/> — the saved
414414
/// reference curve, or a stock read, index-aligned with <paramref name="anchors"/> — invoked
415-
/// lazily, so a document of plain offsets (every export this tool writes) never needs it.
415+
/// lazily, so a document of plain offsets (every export this tool writes) never needs it —
416+
/// and refused when the stock read backing it sits at the idle floor itself, where no offset
417+
/// can be derived (save a reference curve instead).
416418
/// Each resolved clock is held to the planned path's plausible range — a replay must not
417419
/// write offsets no plan could have produced. The range's minimum is not enforced at anchors
418420
/// reading at the curve's floor clock (<see cref="GpuTuning.AtFloorClock"/>): at deep idle —
@@ -443,7 +445,26 @@ public static int[] ResolveCurveOffsetsKhz(TuningDoc doc, IReadOnlyList<(int Mv,
443445
int i = anchorIndices[e];
444446
CurveEntryDoc entry = entries[e];
445447

446-
long offsetMhz = entry.Offset ?? entry.Mhz!.Value - Stock()[i].Mhz;
448+
// An absolute clock derives its offset from the anchor's stock clock, which a
449+
// floor-pinned stock read doesn't hold - the derivation would fold the pinning error
450+
// into the offset (a silent overclock by up to the anchor's whole stock clock), so
451+
// it refuses instead. A saved reference curve, captured awake, resolves it.
452+
long offsetMhz;
453+
if (entry.Offset is { } offset)
454+
{
455+
offsetMhz = offset;
456+
}
457+
else if (GpuTuning.AtFloorClock(Stock(), i))
458+
{
459+
throw new CliError($"{what} sets an absolute clock at the {entry.Mv} mV anchor, "
460+
+ "but the stock clock there currently reads at the idle floor, so the "
461+
+ "offset to write can't be derived - retry with the card awake, or save a "
462+
+ "reference curve first (set-reference-curve).");
463+
}
464+
else
465+
{
466+
offsetMhz = entry.Mhz!.Value - Stock()[i].Mhz;
467+
}
447468

448469
// A replay must not write what no plan could have produced (RunReplay holds the
449470
// memory offset to the same standard). The offset alone is bounded first, so a

‎tests/TuningDocumentsTests.cs‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,39 @@ public void ResolveCurveOffsets_SkipsTheResolvedBoundOnAnUnreadableTable()
452452
Assert.Equal(-2_450_000, Resolve(doc, curve)[10]);
453453
}
454454

455+
[Fact]
456+
public void ResolveCurveOffsets_RefusesAnAbsoluteClockAtAFloorPinnedAnchor()
457+
{
458+
// An absolute clock derives its offset from the stock clock at the anchor, which a
459+
// floor-pinned stock read doesn't hold - deriving against the pinned 202 would turn a
460+
// mild target into a huge positive delta. A named refusal, not a wrong write.
461+
var idle = TestCurves.IdleFloorPinned(pinned: 8, floorMhz: 202);
462+
var doc = new TuningDoc
463+
{
464+
Curve = new[] { new CurveEntryDoc { Mv = idle[5].Mv, Mhz = 900 } },
465+
};
466+
467+
Assert.Throws<CliError>(() => Resolve(doc, idle));
468+
}
469+
470+
[Fact]
471+
public void ResolveCurveOffsets_ResolvesAnAbsoluteClockAgainstASavedReferenceAtIdle()
472+
{
473+
// With a saved reference the stock clock is known regardless of power state: the offset
474+
// derives from the reference, and the pinned anchor's minimum exemption lets the small
475+
// result through.
476+
var idle = TestCurves.IdleFloorPinned(pinned: 8, floorMhz: 202);
477+
var reference = TestCurves.Realistic();
478+
var doc = new TuningDoc
479+
{
480+
Curve = new[] { new CurveEntryDoc { Mv = idle[5].Mv, Mhz = reference[5].Mhz - 120 } },
481+
};
482+
483+
int[] deltasKhz = TuningDocuments.ResolveCurveOffsetsKhz(doc, idle, () => reference, "The tuning");
484+
485+
Assert.Equal(-120_000, deltasKhz[5]);
486+
}
487+
455488
private static int[] Resolve(TuningDoc doc, IReadOnlyList<(int Mv, int Mhz)> stock)
456489
=> TuningDocuments.ResolveCurveOffsetsKhz(doc, stock, () => stock, "The tuning");
457490

0 commit comments

Comments
 (0)