Standing goals - re-verify done, forever
TASK-IMP-109: Standing goals - re-verify done, forever
Summary
done is terminal and never re-checked. TRACE-004 proves every clause had a passing test on the day it shipped and nothing looks again, so a task shipped in batch 1 could be broken today and the corpus would still show it green. At the done flip, enrol the task's cited tests as a standing goal, and re-run the goals on demand. Detection only: a violated goal becomes a type: bug task through the normal loop, never an auto-fix.
Problem
A goal verified once is an assumption with a timestamp. Every acceptance this run recorded is exactly that: true on 2026-07-17, unexamined on 2026-07-18.
task-reconcile (v2.7.0) does not close this. It measures drift when a task RE-ENTERS the workflow - it is a turnstile, not a sentinel. A done task that never comes back is never looked at again by anything.
The corpus already demonstrates the failure mode: TASK-IMP-086 recorded acceptance evidence for rows that were not in the committed file, and nothing re-checked until an external reviewer asked. That was caught by luck and a bot. The 35 done improvement tasks and 176 done tasks overall currently rest on the same footing.
Proposed Solution
At the done flip, ship-tasks writes docs/goals/<task-id>.md carrying the task's §1 cited tests as its predicate - free, because TRACE-004 already collected exactly that list. A verify-goals.mjs runner re-runs each predicate, flips a failing goal to violated, and appends to a goal ledger. A violated goal produces a finding, and the fix goes through create-tasks -> ship-tasks like any other bug.
Only mechanically re-runnable predicates are enrolled. ACs carrying a justified verify: rather than test: cannot be re-run by a script, and the goal file MUST say so rather than pretend - an honest gap beats a fake predicate.
Alternatives Considered
- Re-run the whole suite instead of per-task goals. Rejected: it answers "is the repo green", not "is TASK-X still true", and it cannot name which acceptance decayed.
- Auto-fix on violation. Rejected outright: the sentinel detects, the pipeline fixes. An auto-fix on a violated acceptance is the machine grading its own homework at the one moment nobody is watching.
- Re-open the original task on violation. Rejected:
doneis terminal for a reason, and reviving a shipped task destroys the record of what was accepted. A newtype: bugtask preserves both. - Cron the runner. Rejected in scope: scheduling is a host decision and CyberOS is invoked, not daemonised. The runner is a command; when it runs is the operator's business.
Success Metrics
- Primary: a task flipped to
donegains a goal file whose predicate is its §1 cited tests, and breaking one of those tests flips the goal toviolatedon the next run - suite-asserted. Baseline:doneis never re-checked. - Guardrail: a violated goal changes no task status and writes no code - it emits a finding and nothing else.
Scope
In scope: goal emission at the done flip, verify-goals.mjs, the goal ledger, the report, suite arms.
Out of scope / Non-Goals
- Any auto-fix, auto-revert, or status change on violation.
- Scheduling (cron, CI wiring) - the runner is a command.
- Enrolling
verify:-only ACs as predicates (they are not mechanically re-runnable; the goal names the gap). - Retiring goals automatically - retirement is a human decision, logged.
Dependencies
None mechanically. Consumes the §1 cited tests TRACE-004 already collects.
Serialisation note: touches STATUS-REFERENCE.md and ship-tasks.md, both shared with TASK-IMP-108 (and ship-tasks with 113, 114, 115). Parent-serialised per §11a; never concurrent.
AI Authorship Disclosure
- Tools used: Claude (Fable 5) running the CyberOS task-author skill inside Cowork.
- Scope: spec drafted from IMPROVEMENT_HANDOFF.md §11 IMP-29, itself derived from the agentic-OS builder's guide (Avid, 2026-07-06) BUILD 5; verified against ship-tasks.md and task-reconcile.mjs on merged main.
- Human review: scope approved at the 2026-07-17 PLAN gate; both HITL gates are recorded human verdicts.
1. Description (normative)
- 1.1 On the
doneflip, ship-tasks MUST writedocs/goals/<task-id>.mdcarrying: the predicate (the task's §1 cited tests),born,source(the task id),status: satisfied,last_pass, andon_violation(default: report, never auto-fix). - 1.2 The predicate MUST be derived from the §1 cited tests TRACE-004 already verified - this task MUST NOT invent a predicate the task never claimed.
- 1.3 ACs whose evidence is a justified
verify:rather than atest:MUST NOT be enrolled as predicates, and the goal file MUST name them as not mechanically re-verifiable. - 1.4 A task reaching
donewith zero mechanically re-runnable predicates MUST still get a goal file, markedpredicate: nonewith the reason - the absence is the finding. - 1.5
verify-goals.mjsMUST re-run each non-retired goal's predicate, flip failures tostatus: violated, refreshlast_passon success, and append one row per goal todocs/goals/.ledger.tsv. - 1.6
verify-goals.mjsMUST exit non-zero when any goal is violated, and MUST print each violated goal with its task id and the failing predicate. - 1.7 A violated goal MUST NOT change any task's status, MUST NOT modify code, and MUST NOT re-open the source task. The remedy is a new
type: bugtask through create-tasks. - 1.8 A predicate exceeding its timeout MUST be treated as violated and named as a timeout - an unrunnable predicate is not a passing one.
2. Acceptance criteria
- [ ] AC 1 (traces_to: #1.1, #1.2) - a
doneflip writes a goal file whose predicate is the task's §1 cited tests - test:tools/install/tests/test_verify_goals.sh::t01_done_emits_goal - [ ] AC 2 (traces_to: #1.5, #1.6) - breaking a cited test flips the goal to violated, appends a ledger row, and exits non-zero naming the task - test:
tools/install/tests/test_verify_goals.sh::t02_broken_test_violates - [ ] AC 3 (traces_to: #1.5) - a passing goal refreshes
last_passand stays satisfied - test:tools/install/tests/test_verify_goals.sh::t03_passing_refreshes - [ ] AC 4 (traces_to: #1.3, #1.4) - a
verify:-only AC is not enrolled and is named; a task with no runnable predicate still gets apredicate: nonegoal - test:tools/install/tests/test_verify_goals.sh::t04_unrunnable_named_not_faked - [ ] AC 5 (traces_to: #1.7) - a violated goal changes no task status and writes no code - test:
tools/install/tests/test_verify_goals.sh::t05_detection_only - [ ] AC 6 (traces_to: #1.8) - a predicate that hangs is violated and named as a timeout - test:
tools/install/tests/test_verify_goals.sh::t06_timeout_is_violation
3. Edge cases
- A cited test that is later legitimately renamed: the goal breaks and is violated. Correct - the acceptance now cites a test that does not exist, and that IS a finding. The remedy is an operator retiring or amending the goal, logged.
- A flaky cited test: it violates intermittently and poisons the ledger. Quarantine (
status: retired, reason recorded), never silent deletion - a goal deleted without a reason is the 086 pattern. - 176 existing
donetasks have no goal files: they are not backfilled by this task (out of scope) and the runner MUST NOT claim coverage it does not have. The report states how manydonetasks have no goal. - A goal whose predicate needs a service, credential, or network: it fails in a clean checkout. 1.3's rule applies - if it is not cheap, deterministic, and read-only, it is not a predicate.
- Predicate confinement: goals are files in the repo, and their predicates are commands. They MUST be confined and tracked-checked exactly as TASK-IMP-100's rung-5 requires - a goal file is INPUT, and a crafted predicate must never execute. This is the same defect the batch-5 review caught in
task-reconcile, and it MUST NOT be re-introduced here. - Security-class: HIGH by construction - this task executes commands read from files. Every predicate MUST resolve under the repo root, MUST be
git ls-tree HEAD-tracked, and MUST run without a shell where possible. This is the task's central risk and its central test.
Audit
§1 - Verdict summary
Spec is 96 lines, 8 §1 clauses, 6 ACs, 6 edge cases. Converts done from a claim into a maintained invariant using predicates TRACE-004 already collects. Highest-risk task in the batch by construction - it executes commands read from files. Passes after 8 findings.
§2 - Findings (all resolved)
ISS-001 - Executing predicates read from files is the rung-5 defect, re-introduced
This task's core mechanism - run a command named in a repo file - is exactly what the batch-5 review caught in task-reconcile: a crafted file could name a command. Resolved: §3 security-class is marked HIGH and requires repo-root confinement plus a git ls-tree HEAD tracked check before execution, naming the precedent so the fix is not re-derived from scratch.
ISS-002 - Auto-fix on violation would be the machine grading itself
An auto-fix on a violated acceptance is self-certification at the exact moment nobody is watching. Resolved: §1 #1.7 forbids status change, code change, and re-opening; AC 5 asserts detection-only.
ISS-003 - verify:-only ACs cannot be predicates but could be faked as ones
A predicate that cannot be re-run is not a predicate. Resolved: §1 #1.3 excludes them and requires the goal to name the gap; §1 #1.4 covers the zero-predicate task with predicate: none rather than a fake pass.
ISS-004 - A hanging predicate could be read as passing
A timeout returning nothing is not a success. Resolved: §1 #1.8 makes timeout a violation, named as such; AC 6 asserts it.
ISS-005 - Re-opening the source task would destroy the acceptance record
done is terminal for a reason. Resolved: §1 #1.7 requires a new type: bug task through the normal loop.
ISS-006 - 176 existing done tasks have no goals - the report could imply coverage
Claiming a guarantee covering a third of the corpus would be the 086 pattern. Resolved: §3 requires the report to state how many done tasks have no goal; backfill is an explicit Non-Goal.
ISS-007 - A flaky predicate would poison the ledger and invite deletion
A goal deleted without a reason is the evidence loss this task exists to prevent. Resolved: §3 requires quarantine with a recorded reason, never silent deletion.
ISS-008 - Scheduling would couple the payload to a host
Cron is a host decision; CyberOS is invoked. Resolved: explicit Non-Goal - the runner is a command, and when it runs is the operator's business.
§3 - Resolution
All 8 concerns addressed. The machine floor (task-lint) ran FIRST and was clean before any judgment family was applied, per TASK-IMP-084. Score = 10/10.
End of TASK-IMP-109 audit.