The Vacuous Success Bug: When Empty Plans Count as Achievements
A Python truth-value edge case caused every user commitment to be silently filed as a completed achievement within 400 milliseconds, permanently poisoning the proactive follow-up pipeline.
- Reference
- A001
- Project
- ÆON
- Status
- Fixed
- Evidence
- high
- Source
- 001-vacuous-success-bug.md
Context
Ashi is a personal AI system with a planning layer (ashi-planning) that creates Plan objects attached to Goal records. A ProactiveCognitionRuntime was designed to sweep through open goals and surface reminders or initiate check-ins. The architecture was complete, tested, and certified — the bug lived somewhere else entirely.
The Question
Why did Ashi never initiate a proactive contact in its entire operational lifetime, despite having a working ProactiveCognitionRuntime?
Initial Approach
The assumption was that the proactive runtime had a bug or was not properly wired. A forensic audit of the running system (ashi serve instance, real Gemini, real Postgres, ~2,941 memory records, 22 live turns) examined persisted state directly.
What Happened
A forensic trace of the live database revealed:
23 of 26 plans ever created contained zero steps. 100% of those goals were recorded as ACHIEVED.The timeline for one representative case: user said "Remind me tomorrow to re-run the inference benchmark." Ashi responded: "I've queued the reminder to re-run the inference benchmark tomorrow for your approval."
- Goal
f7713c52created at 17:57:19.83 - Goal status set to
ACHIEVEDat 17:57:20.20 - Elapsed: ~370 milliseconds
pending_approvalscount: unchanged (zero approvals created)- Attached plan
cfc76e60had"steps": []
When asked immediately afterward: "Is there anything you were supposed to follow up on?", Ashi answered:
"No, there are no pending follow-ups... explicit follow-up tasks—such as re-running the inference benchmark tomorrow—are captured as reminders rather than left as open loops, ensuring nothing slips through the cracks while you rest."
It denied having the follow-up, named the exact follow-up it had discarded, and reassured the user about the reliability of the mechanism that discarded it.
Evidence
apps/ashi/src/ashi/app/operator/operator.py:792— the exact line wherestop_reason == COMPLETEDled toGoalStatus.ACHIEVEDapps/ashi/src/ashi/app/planning/pipeline_stage.py:75— injected the "tell the user the action is queued" instruction regardless of whether a proposal was persisted- Live database query:
select count(*) from pending_approvalsshowed unchanged count after three separate "queue this" interactions proactive/runtime.py:138—ProactiveCognitionRuntime.run_sweep()filters outACHIEVEDgoals by design (correct behavior; wrong input)reports/behavioral-audit/BEHAVIORAL_INTEGRITY_AUDIT.md— full documented audit- Phase T ADR
docs/decisions/0132-phase-t-action-integrity-and-commitment-durability.md
Diagnosis
Established:
all(step.status is COMPLETED for step in plan.steps) evaluates to True over an empty list in Python. This is standard Python semantics — all([]) is True by mathematical convention (vacuous truth). The completion check in operator.py was correct Python; it was logically wrong for this domain.
An empty plan therefore always "completed." A completed plan caused the goal to be marked ACHIEVED. ACHIEVED goals are permanently excluded from the proactive sweep. Every commitment ever stated was filed as an accomplishment within milliseconds.
Likely:
The test suite had never exercised this path with an empty plan, because unit tests of the completion logic were not constructed adversarially (empty-plan case).
Unknown:
When exactly this bug was introduced. No git-bisect analysis was conducted.
What Changed
Phase T introduced T1:
- Empty plan →
NO_ACTION_PROPOSALstatus (notCOMPLETED) ACHIEVEDnow requires_has_execution_evidence— at least one successfully executed step record must existPlanExecutionStagewas wired to be a truth boundary: claims about queued actions require a real persistedpending_approval_id
What I Learned
The proactive pipeline was not broken — it was starved by correct behavior operating on wrong inputs. The entire initiative, follow-up, and commitment retention system had been performing exactly as designed on data that was permanently invalid.
The gap between "this subsystem runs" and "this subsystem has something meaningful to run on" is a separate failure mode from "this subsystem is broken," and tests that exercise the subsystem in isolation cannot catch it.
What I Would Do Differently
The all(steps) check needed a precondition: require len(steps) > 0 before evaluating completion. This is a domain constraint, not a Python constraint, and should have been expressed explicitly with an assertion or guard clause.
More broadly: any system where "doing nothing" is semantically equivalent to "completing the task successfully" needs an explicit marker for the "nothing was done" case. Silent empty completions are a failure mode class, not a single bug.
Broader Principle
Vacuous truth in completion checks is an architectural hazard. In Python, all([]) is True. sum([]) is 0. Any system that computes success from an aggregate over a collection must explicitly guard the empty-collection case if "empty collection" and "nothing to do" are not equivalent to "success." This is particularly dangerous in planning, commitment, and approval systems, where the empty case is the precise failure mode to guard against.
Technical References
apps/ashi/src/ashi/app/operator/operator.py:792apps/ashi/src/ashi/app/planning/pipeline_stage.py:75packages/ashi-planning/src/ashi/planning/formation.py:114apps/ashi/src/ashi/app/planning/proactive/runtime.py:138docs/decisions/0132-phase-t-action-integrity-and-commitment-durability.mdreports/behavioral-audit/BEHAVIORAL_INTEGRITY_AUDIT.md
Failure sequence
On the record- Attempt
- The assumption was that the proactive runtime had a bug or was not properly wired. A forensic audit of the running system (`ashi serve` instance, real Gemini, real Postgres, ~2,941 memory records, 22 live turns) examined persisted state directly.
- Failure
- A forensic trace of the live database revealed: > **23 of 26 plans ever created contained zero steps. 100% of those goals were recorded as `ACHIEVED`.** The timeline for one representative case: user said "Remind me tomorrow to re-run the inference benchmark." Ashi responded: "I've queued the reminder to re-run the inference benchmark tomorrow for your approval." - Goal `f7713c52` created at 17:57:19.83 - Goal status set to `ACHIEVED` at 17:57:20.20 - **Elapsed: ~370 milliseconds** - `pending_approvals` count: unchanged (zero approvals created) - Attached plan `cfc76e60` had `"steps": []` When asked immediately afterward: "Is there anything you were supposed to follow up on?", Ashi answered: > "No, there are no pending follow-ups... explicit follow-up tasks—such as re-running the inference benchmark tomorrow—are captured as reminders rather than left as open loops, ensuring nothing slips through the cracks while you rest." It denied having the follow-up, named the exact follow-up it had discarded, and reassured the user about the reliability of the mechanism that discarded it.
- Diagnosis
- **Established:** `all(step.status is COMPLETED for step in plan.steps)` evaluates to `True` over an empty list in Python. This is standard Python semantics — `all([])` is `True` by mathematical convention (vacuous truth). The completion check in `operator.py` was correct Python; it was logically wrong for this domain. An empty plan therefore always "completed." A completed plan caused the goal to be marked `ACHIEVED`. `ACHIEVED` goals are permanently excluded from the proactive sweep. Every commitment ever stated was filed as an accomplishment within milliseconds. **Likely:** The test suite had never exercised this path with an empty plan, because unit tests of the completion logic were not constructed adversarially (empty-plan case). **Unknown:** When exactly this bug was introduced. No git-bisect analysis was conducted.
- Lesson
- The proactive pipeline was not broken — it was starved by correct behavior operating on wrong inputs. The entire initiative, follow-up, and commitment retention system had been performing exactly as designed on data that was permanently invalid. The gap between "this subsystem runs" and "this subsystem has something meaningful to run on" is a separate failure mode from "this subsystem is broken," and tests that exercise the subsystem in isolation cannot catch it.
- Next iteration
- Phase T introduced `T1`: - Empty plan → `NO_ACTION_PROPOSAL` status (not `COMPLETED`) - `ACHIEVED` now requires `_has_execution_evidence` — at least one successfully executed step record must exist - `PlanExecutionStage` was wired to be a truth boundary: claims about queued actions require a real persisted `pending_approval_id`