Include hardware details in feedback submissions (#1726)

Add chip (e.g. Apple M1 Pro), RAM, hardware model, architecture
(arm64/x86_64), and display info to feedback metadata. All fields are
non-sensitive system properties collected via sysctlbyname, ProcessInfo,
and NSScreen. Server-side route accepts and renders the new fields in
both plain text and HTML email bodies.

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
This commit is contained in:
Lawrence Chen 2026-03-18 02:59:16 -07:00 committed by GitHub
parent 0a99bb504c
commit de1aa7a6ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 96 additions and 3 deletions

View file

@ -8400,6 +8400,11 @@ private struct FeedbackComposerAppMetadata {
let bundleIdentifier: String
let osVersion: String
let localeIdentifier: String
let hardwareModel: String
let chip: String
let memoryGB: String
let architecture: String
let displayInfo: String
static var current: FeedbackComposerAppMetadata {
let infoDictionary = Bundle.main.infoDictionary ?? [:]
@ -8414,9 +8419,50 @@ private struct FeedbackComposerAppMetadata {
appCommit: commit ?? "",
bundleIdentifier: Bundle.main.bundleIdentifier ?? "",
osVersion: ProcessInfo.processInfo.operatingSystemVersionString,
localeIdentifier: Locale.preferredLanguages.first ?? Locale.current.identifier
localeIdentifier: Locale.preferredLanguages.first ?? Locale.current.identifier,
hardwareModel: sysctlString("hw.model") ?? "",
chip: sysctlString("machdep.cpu.brand_string") ?? "",
memoryGB: formatMemoryGB(),
architecture: currentArchitecture(),
displayInfo: currentDisplayInfo()
)
}
private static func sysctlString(_ name: String) -> String? {
var size = 0
guard sysctlbyname(name, nil, &size, nil, 0) == 0, size > 0 else { return nil }
var buffer = [CChar](repeating: 0, count: size)
guard sysctlbyname(name, &buffer, &size, nil, 0) == 0 else { return nil }
return String(cString: buffer).trimmingCharacters(in: .whitespacesAndNewlines)
}
private static func formatMemoryGB() -> String {
let bytes = ProcessInfo.processInfo.physicalMemory
let gb = Double(bytes) / (1024 * 1024 * 1024)
return "\(Int(gb)) GB"
}
private static func currentArchitecture() -> String {
#if arch(arm64)
return "arm64"
#elseif arch(x86_64)
return "x86_64"
#else
return "unknown"
#endif
}
private static func currentDisplayInfo() -> String {
let screens = NSScreen.screens
let descriptions = screens.map { screen -> String in
let frame = screen.frame
let scale = screen.backingScaleFactor
return "\(Int(frame.width))x\(Int(frame.height)) @\(Int(scale))x"
}
let count = screens.count
let prefix = "\(count) display\(count == 1 ? "" : "s")"
return "\(prefix), \(descriptions.joined(separator: "; "))"
}
}
private enum FeedbackComposerSubmissionError: Error {
@ -8470,6 +8516,11 @@ private enum FeedbackComposerClient {
appendField("bundleIdentifier", value: metadata.bundleIdentifier, to: &body, boundary: boundary)
appendField("osVersion", value: metadata.osVersion, to: &body, boundary: boundary)
appendField("locale", value: metadata.localeIdentifier, to: &body, boundary: boundary)
appendField("hardwareModel", value: metadata.hardwareModel, to: &body, boundary: boundary)
appendField("chip", value: metadata.chip, to: &body, boundary: boundary)
appendField("memoryGB", value: metadata.memoryGB, to: &body, boundary: boundary)
appendField("architecture", value: metadata.architecture, to: &body, boundary: boundary)
appendField("displayInfo", value: metadata.displayInfo, to: &body, boundary: boundary)
for attachment in preparedAttachments {
appendFile(