Introduces a SwiftUI companion app for the Fail Well PWA: menu bar status item, popover with task list / record / history views, command palette, and a Dynamic Island-style notch overlay that shows the active step and timer beside the hardware notch and expands on hover to reveal pause/next controls.
52 lines
2.5 KiB
Swift
52 lines
2.5 KiB
Swift
import Testing
|
|
@testable import FailWell
|
|
|
|
@Suite("TaskPlan — Initial Plan baseline")
|
|
struct TaskPlanTests {
|
|
@Test func initialEstimationReturnsInitialPlanValueAfterReestimation() {
|
|
// CONTEXT.md §"Failure Signal" — the honest baseline is the Initial Plan,
|
|
// even after the developer re-estimates mid-Execution.
|
|
let initialSteps = StepParser.adaptTextareaToSteps("- refactor parser | 5")
|
|
var task = TaskPlan(id: "t1", title: "Test", stepHistory: [initialSteps])
|
|
|
|
// Re-estimate: same title, new estimation → same Step id, new Step entry.
|
|
let reestimated = StepParser.adaptTextareaToSteps("- refactor parser | 12")
|
|
task.newSteps(reestimated)
|
|
|
|
let stepId = task.steps[0].id
|
|
#expect(initialSteps[0].id == stepId) // identity preserved across re-estimation
|
|
#expect(task.steps[0].estimation == 12) // current Plan reflects the new number
|
|
#expect(task.initialEstimation(for: stepId) == 5) // baseline reflects the commitment
|
|
}
|
|
|
|
@Test func initialEstimationReturnsNilForStepsAddedMidExecution() {
|
|
let initialSteps = StepParser.adaptTextareaToSteps("- planned step | 5")
|
|
var task = TaskPlan(id: "t1", title: "Test", stepHistory: [initialSteps])
|
|
|
|
let addedLater = StepParser.adaptTextareaToSteps("""
|
|
- planned step | 5
|
|
- unplanned step | 3
|
|
""")
|
|
task.newSteps(addedLater)
|
|
|
|
let addedStepId = task.steps[1].id
|
|
#expect(task.initialEstimation(for: addedStepId) == nil) // no baseline → no Failure Signal
|
|
}
|
|
|
|
@Test func failureSignalFiresAgainstInitialPlanNotCurrent() {
|
|
// Scenario from the CONTEXT.md challenge: planned 5m, drifted, re-estimated to 12m,
|
|
// finished at 12m. Honest signal must fire because we missed the *original* commitment.
|
|
let initialSteps = StepParser.adaptTextareaToSteps("- step | 5")
|
|
var task = TaskPlan(id: "t1", title: "Test", stepHistory: [initialSteps])
|
|
task.newSteps(StepParser.adaptTextareaToSteps("- step | 12"))
|
|
|
|
let stepId = task.steps[0].id
|
|
let baseline = task.initialEstimation(for: stepId)!
|
|
let actualMinutes = 12.0
|
|
|
|
#expect(EstimationComparator.is10PercentOff(estimation: Double(baseline), duration: actualMinutes) == true)
|
|
// Confirm the silent-signal bug: comparing against the *current* (re-estimated) value would hide it.
|
|
#expect(EstimationComparator.is10PercentOff(estimation: Double(task.steps[0].estimation), duration: actualMinutes) == false)
|
|
}
|
|
}
|