v0.318.0: the internal data place, partitions, an honest whole-box backup offer (R-1084), sys_drive never offered (R-1082)
gates / gates (push) Successful in 46s

felhom.eu architecture/16 §4-§6 (build B). MinAgent 0.157.0 — the internal place and the partitions appear only when
agent >= 0.158.0 reports them. Tests red-proved; four parity fixtures refreshed (only the new lines).

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-16 03:57:49 +02:00
parent 123d2d553f
commit a43d0423d5
28 changed files with 913 additions and 26 deletions
@@ -190,6 +190,12 @@ func dropRegisteredDrives(resp agentapi.CandidatesResult, mountsText string, reg
out := make([]agentapi.DiskCandidate, 0, len(in))
for _, c := range in {
if candidateBacksInUse(c, inUse) {
// `16` §6 (v0.318.0): a disk whose ONE part is a registered drive keeps its FREE parts on offer —
// the whole disk itself, never (WholeDiskInUse; handleStorageInit refuses it server-side too).
if free := freePartitions(c.Partitions, inUse); len(free) > 0 {
c.Partitions, c.WholeDiskInUse = free, true
out = append(out, c)
}
continue
}
out = append(out, c)
@@ -201,6 +207,34 @@ func dropRegisteredDrives(resp agentapi.CandidatesResult, mountsText string, reg
return resp
}
// deviceBacksRegistered reports whether formatting `device` would touch a registered drive: the device itself, or a
// whole disk one of whose parts is registered (the same join as dropRegisteredDrives). FAIL-SAFE: an unreadable mount
// table cannot prove the device free → true.
func deviceBacksRegistered(device, mountsText string, registered map[string]bool) bool {
if strings.TrimSpace(mountsText) == "" {
return true
}
inUse := map[string]bool{}
for _, row := range parseMountTable(mountsText) {
if registered[path.Clean(row[1])] && strings.HasPrefix(row[0], "/dev/") {
inUse[row[0]] = true
}
}
return candidateBacksInUse(agentapi.DiskCandidate{Device: device}, inUse)
}
// freePartitions keeps the parts that are not a registered drive and not already Felhom's (state in_use).
func freePartitions(parts []agentapi.CandidatePartition, inUse map[string]bool) []agentapi.CandidatePartition {
var out []agentapi.CandidatePartition
for _, p := range parts {
if p.State == agentapi.PartInUse || inUse[p.Device] {
continue
}
out = append(out, p)
}
return out
}
// candidateBacksInUse reports whether a candidate's disk is a source in inUse: the whole disk itself,
// its mountable partition, or any partition of it (/dev/sdb1, /dev/nvme0n1p1 under /dev/sdb, /dev/nvme0n1).
func candidateBacksInUse(c agentapi.DiskCandidate, inUse map[string]bool) bool {