Corpus hygiene - UNREVIEWED fork, module-case lint, stuck-WIP triage
TASK-IMP-139: Corpus hygiene - UNREVIEWED disposition, module-case lint, stuck-WIP triage
Summary
Three corpus-integrity debts: 170 non-draft specs (151 of them done) still carry the # UNREVIEWED markers the 2026-07-14 migration attached to compliance fields with the instruction "a human MUST confirm before this task leaves draft" - so the corpus's ai_authorship and eu_ai_act_risk_class claims on shipped work are unconfirmed and every one of those files fails FM-112 if linted; 251 specs carry mixed-case module: values with no lint rule guarding the field; and 12 tasks sit in implementing - eleven since mid-May - with every forward mid-state otherwise unoccupied, evidence the full lifecycle is rarely exercised and stale WIP accumulates silently. This task dispositions the markers under an explicit operator fork (bulk-clear with recorded verdict vs re-audit wave), normalizes module case and adds the missing lint rule, and triages the 12 via task-reconcile with per-task operator verdicts.
Implementation note: two operator gates inside this task
Gate 1 - the UNREVIEWED fork (do not pre-empt). The marker disposition is a process decision the operator must make explicitly, recorded as a dated source_decisions entry on this spec before any marker is touched:
- Branch clear: one recorded bulk verdict ("the operator accepts the migrated
ai_authorship/eu_ai_act_risk_classvalues on the enumerated 170 files as-is") authorizes removing all markers mechanically; the verdict text ships in the commit body and CHANGELOG. Cheap, honest about being a batch acceptance, leaves per-file confirmation undone forever. - Branch re-audit: a wave re-runs task-audit's compliance families over the 170 files, confirming or correcting the two fields per file before its markers drop; markers survive on any file whose fields a human has not yet confirmed. Expensive, produces real per-file confirmation.
Gate 2 - the stuck-WIP triage (per-task verdicts). Each of the 12 implementing tasks gets a task-reconcile evidence report (what the ladder says actually shipped vs the status), and the operator records ONE verdict per task - resume / route back per STATUS-REFERENCE §1.3 / on_hold - via the standard override path (which emits memory.status_overridden once TASK-CUO-303 lands, or its documented equivalent before). This task performs no status flip on its own authority; TASK-APP-001 (July-created) is expected to be a legitimate resume, which is exactly why the verdicts are per-task, not batch.
Problem
Verified first-hand 2026-07-23:
- Compliance fields unconfirmed at scale (audit H2). The migration marked every auto-set
ai_authorship/eu_ai_act_risk_classwith# UNREVIEWED ... a human MUST confirm before this task leaves draft. 170 files left draft anyway - 151 all the way todone. FM-112 exists precisely to stop this (error, marker past draft) but only fires when the linter runs against a file, which happens at authoring/audit time, not retroactively over the corpus. The EU-AI-Act-adjacent fields on shipped work are, today, machine guesses wearing confirmed clothes. module:field ungoverned. 251 files saymodule: AUTH-style uppercase inside lowercase folders. Nothing breaks loudly (the regenerator groups by folder), but the field feeds the status hub and any future module-scoped tooling, and task-lint has NO rule for it - the only frontmatter field of its kind with zero validation.- Stale WIP, invisible. 11 of 12
implementingtasks are ~10 weeks old with zero forward mid-states occupied corpus-wide; either work stalled silently or statuses were never advanced. Both are lifecycle-integrity failures, and nothing surfaces them (the stuck-WIP sentinel is a 1.4.x roadmap item; this triage is the manual pass that clears today's backlog of doubt).
Proposed Solution
Markers: enumerate the 170 files mechanically (the enumeration script ships in the test suite so review sees the exact set); halt at Gate 1 for the fork verdict; execute the chosen branch; either way the end state is zero # UNREVIEWED markers on non-draft specs whose fields carry a recorded confirmation trail, and FM-112 keeps guarding the future. Module case: one mechanical commit lowercasing the 251 module: values; add a task-lint rule (next free FM id per the rubric's numbering, documented in RUBRIC.md in the same change per the lint-and-rubric-ship-together discipline) asserting module: is lowercase AND equals the containing docs/tasks/<module>/ folder name; regen + status hub verified unchanged (the field now matches what the folder always said). Triage: run task-reconcile per stuck task, attach each evidence report to the triage record, halt at Gate 2 for per-task verdicts, and apply exactly the operator's verdicts through the standard paths. Guard: scripts/tests/test_corpus_hygiene.sh pins the end states - zero non-draft markers, zero module-case mismatches, lint rule fires on fixtures - and rides run_all.sh's glob so regression is loud.
Alternatives Considered
- Author picks the marker branch (bulk-clear, it's cheaper). Rejected: the plan's approval boundary explicitly reserves "the T9 UNREVIEWED bulk decision" as an operator fork; a batch acceptance of compliance fields is a liability posture only the operator can adopt.
- Silently drop the markers as lint noise. Rejected: the marker IS the record that a human never confirmed the fields; deleting it without a verdict manufactures confirmation - the exact laundering FM-112 exists to prevent.
- Make the module-case rule warning-severity. Rejected: after the normalization commit the corpus is 100% conformant, so error-severity costs nothing and prevents re-drift; a warning would be the always-ignorable kind.
- Batch verdict for the 12 stuck tasks ("route all back"). Rejected: the set is heterogeneous - TASK-APP-001 is nine days old and plausibly live; the OBS/MCP eleven may have real partial implementations the evidence ladder will surface. Twelve two-minute decisions beat one wrong batch decision.
- Build the stuck-WIP sentinel (auto-detection) in this task. Rejected: roadmap 1.4.x per the audit; this task clears the existing debt manually and leaves automated detection to its own spec (G13 in TASK-IMP-140 defines the gate; the hub work is future).
Success Metrics
- Primary: by the next CyberOS release - zero
# UNREVIEWEDmarkers on non-draft specs (from 170 files / 336 markers), zero mixed-casemodule:values (from 251), the new lint rule live in task-lint + RUBRIC.md, and all 12 formerly-stuck tasks carrying a dated per-task verdict record with statuses reflecting those verdicts. Baselines as measured 2026-07-23. - Guardrail:
python3 scripts/migrate_improvement_to_task.py --backlogoutput is byte-stable across the normalization (module grouping comes from folders, which do not change), and no task'sstatuschanges except through a recorded Gate-2 verdict.
Scope
In scope: the marker enumeration + fork execution, the 251-file normalization, the lint rule + rubric documentation, the 12 reconcile runs + verdict application, the hygiene test suite, CHANGELOG.
Out of scope / Non-Goals
- Re-auditing the CONTENT of any done task beyond the two compliance fields (Branch re-audit confirms fields, not whole specs).
- The automated stuck-WIP sentinel on the status hub (1.4.x; G13's definition lives in TASK-IMP-140).
- Changing FM-112's semantics or the draft-gate rules (TASK-IMP-108 owns status semantics).
- The
memory.status_overriddenemission mechanics - TASK-CUO-303; Gate-2 verdicts use whatever recorded-override path exists when this task runs.
Dependencies
None blocking. Related: TASK-IMP-100/101 (task-reconcile, the Gate-2 instrument), TASK-IMP-108 (status semantics + FM-115/116 the reconcile verdicts may set), TASK-IMP-117 (the FM-001 conformance precedent for corpus-wide frontmatter sweeps - the module-case normalization follows its mechanical-commit pattern).
AI Authorship Disclosure
- Tools used: Claude (Fable 5) running the CyberOS
task-authorskill in Cursor, as the task-authoring wave of the 2026-07-23 hardening plan. - Scope: the 170/336/151 marker census, the 251 module-case census, and the 12-task list with creation dates were measured by script against the working tree at authoring time (the audit's 167/148 and "6 MCP" figures are corrected to measured values, discrepancies recorded in source_pages); no spec's status or content was modified during authoring.
- Human review: the hardening plan was operator-approved 2026-07-23 with the UNREVIEWED fork explicitly reserved; both gates in this spec implement that reservation.
1. Description (normative)
- 1.1 The marker disposition MUST NOT begin until a dated operator verdict selecting Branch clear or Branch re-audit is recorded on this spec; the enumeration of affected files (mechanically derived, 170 at authoring) MUST be attached to the verdict so the operator approves a known set, not a description.
- 1.2 After the chosen branch executes, zero non-draft spec.md files may contain
# UNREVIEWED, and the confirmation trail MUST exist: Branch clear = the bulk verdict text in commit body + CHANGELOG; Branch re-audit = per-file confirmation in each file's audit record. Draft specs keep their markers (FM-112 permits them there; they are honest). - 1.3 All
module:frontmatter values MUST be lowercase and equal to the containingdocs/tasks/<module>/folder name, via one mechanical normalization commit (251 files at authoring). - 1.4
task-lint.mjsMUST gain an error-severity rule (next free FM id) enforcing 1.3's invariant, andmodules/skill/task-audit/RUBRIC.mdMUST document the rule in the same change - the lint and the rubric ship together per the authoring discipline. - 1.5 Each of the 12
implementingtasks MUST receive atask-reconcileevidence report, and any status change MUST be applied only per a recorded per-task operator verdict (resume / route back / on_hold) through the standard override path. This task MUST NOT flip any status on its own authority, and the triage record MUST cover all 12 (a verdict may legitimately be "resume unchanged"). - 1.6 A new suite
scripts/tests/test_corpus_hygiene.shMUST assert: zero non-draft markers corpus-wide; zero module-case mismatches; the lint rule fires on a mixed-case fixture and on a folder-mismatch fixture and passes on a conformant one; and the backlog regenerator is byte-stable across a re-run (idempotence guard). It registers via therun_all.shglob. - 1.7
CHANGELOG.mdMUST record the chosen marker branch, the normalization count, the new lint rule id, and the triage outcome summary (n resumed / n routed back / n held).
2. Acceptance criteria
- [x] AC 1 (traces_to: #1.1) - the spec carries the dated fork verdict with the attached enumeration BEFORE any marker-touching commit (verified in spec + git history at review) - test:
scripts/tests/test_corpus_hygiene.sh::t01_fork_verdict_recorded - [x] AC 2 (traces_to: #1.2) -
grep -rl '# UNREVIEWED' docs/tasks/**/spec.mdintersected with non-draft statuses returns empty, and the branch-appropriate confirmation trail exists (bulk verdict text present, or per-file audit confirmations) - test:scripts/tests/test_corpus_hygiene.sh::t02_no_nondraft_markers - [x] AC 3 (traces_to: #1.3) - a corpus scan finds zero
module:values that are non-lowercase or unequal to their folder name - test:scripts/tests/test_corpus_hygiene.sh::t03_module_case_conformant - [x] AC 4 (traces_to: #1.4) - task-lint exits non-zero naming the new rule id on a mixed-case fixture and on a folder-mismatch fixture, exits 0 on a conformant fixture, and RUBRIC.md documents the id - test:
scripts/tests/test_corpus_hygiene.sh::t04_lint_rule_fires - [x] AC 5 (traces_to: #1.5) - twelve reconcile evidence reports exist, each stuck task has a dated verdict record, every status change in the triage commit maps 1:1 to a verdict, and no other task's status changed - test:
scripts/tests/test_corpus_hygiene.sh::t05_triage_verdict_per_task - [x] AC 6 (traces_to: #1.6) - the suite runs green under
bash scripts/tests/run_all.shdiscovery and the regenerator produces byte-identical BACKLOG.md on consecutive runs post-normalization - test:scripts/tests/test_corpus_hygiene.sh::t06_registered_and_idempotent - [x] AC 7 (traces_to: #1.7) - CHANGELOG's top entry names the branch, the count 251, the rule id, and the triage tally - test:
scripts/tests/test_corpus_hygiene.sh::t07_changelog_records_hygiene
3. Edge cases
- New UNREVIEWED files accrue between authoring and implementation: the enumeration is re-derived at Gate 1 (the 170 is the authoring-time census, not a frozen list); the verdict covers the re-derived set, which is why 1.1 requires attaching it.
- A file is BOTH mixed-case and marker-bearing: the normalization commit is field-mechanical and marker-preserving; order is normalization first (no judgment), markers second (gated) - so the mechanical half never waits on the fork.
_archive/and_audits/trees: the census and the sweeps scope todocs/tasks/*/TASK-*/spec.mdexactly as the layout suite does; archived flat files are historical record and are not rewritten.- A stuck task's reconcile evidence shows it actually FINISHED (code shipped, status never advanced): the ladder surfaces it; the verdict is still the operator's - likely a forward flip through the standard gates with evidence attached, not a silent correction. The spec deliberately does not enumerate verdict outcomes beyond the three canonical ones plus "resume unchanged".
- Branch re-audit finds a genuinely wrong risk class on a done task: correcting the field is in scope (that is the point of the branch); anything larger it uncovers routes to a new task rather than scope-creeping this one.
- Case-only rename collisions on case-insensitive filesystems: no file renames occur - only frontmatter VALUES change; folder names were already lowercase, so APFS/NTFS case folding is never exercised.
- Security-class: text-only corpus edits + read-only evidence tooling; the compliance fields' VALUES change only under recorded human verdicts; no execution surface. The lint rule reduces spoofing surface (a task claiming module
AUTHwhile living inimprovement/now fails loudly).
Audit
§1 — Verdict summary
Seven §1 clauses, seven ACs, seven edge cases. Like TASK-IMP-138, this task carries operator gates INSIDE its implementation (the UNREVIEWED fork, the per-task triage verdicts) and the audit's first job was verifying the spec forces those gates mechanically rather than trusting the implementer's manners. Second job: measurement honesty - the audit-report figures (167 files, 148 done, "6 MCP") were all corrected to fresh measurements (170, 151, 5 MCP + 6 OBS + 1 APP) with the discrepancies recorded in source_pages.
§2 — Findings (all resolved)
ISS-001 — the fork could be pre-empted by an implementer with an opinion
"Operator decides the marker disposition" without an ordering clause lets a queue-picked implementer bulk-clear first and record a verdict after. Resolved: clause 1.1 makes the dated verdict + attached enumeration a MUST-precondition to any marker-touching commit; AC 1 verifies precedence via spec + git history at review.
ISS-002 — the verdict would have covered a description, not a set
"Clear the ~170 files" approves a moving target; files accrue markers between authoring and implementation (three did between audit and authoring). Resolved: 1.1 requires attaching the re-derived enumeration to the verdict; the edge case names the re-derivation explicitly.
ISS-003 — batch-verdict temptation on the 12 stuck tasks
The plan's phrasing ("triage the 12") invites one collective route-back - and the measured set contains TASK-APP-001, created nine days ago, plausibly live. A batch verdict would route back genuinely in-flight work. Resolved: clause 1.5 + the implementation note require per-task verdicts; Alternatives records why batch was rejected; "resume unchanged" is named as a legitimate verdict so the record can be complete without forced motion.
ISS-004 — silent-status-change risk in the triage commit
A triage that flips statuses "per verdicts" needs a mechanical check that no OTHER status moved in the same commit. Resolved: AC 5 asserts the 1:1 verdict-to-change mapping AND that no unlisted task's status changed.
ISS-005 — normalization vs marker-sweep ordering was undefined
Both sweeps touch overlapping files; if the gated marker work blocks the mechanical case fix, 251 files wait on a fork that has nothing to do with them. Resolved: edge case pins normalization-first (mechanical, ungated) with markers second (gated) - the fork never blocks the mechanical half.
ISS-006 — lint rule needed the folder-equality half, not just lowercase
module: auth inside docs/tasks/improvement/ is lowercase and still wrong; the real invariant is field == folder. Resolved: clause 1.3/1.4 pin both halves; AC 4 tests a folder-mismatch fixture separately from the case fixture.
ISS-007 — case-insensitive-filesystem hazard checked and discharged
A case sweep that renamed FILES would hit APFS case-folding hazards. Verified: only frontmatter VALUES change; folders were already lowercase. Resolved as an explicit edge case so the implementer doesn't "helpfully" rename anything.
§3 — TRACE-006 semantic sufficiency (per clause)
| Clause | Verb demand | Cited test asserts | Verdict |
|---|---|---|---|
| 1.1 MUST NOT begin markers until verdict + enumeration recorded | verdict precedence + attached set | AC 1: asserts both (review-time inspection + t01 presence) | sufficient |
| 1.2 zero non-draft markers + confirmation trail | empty census + branch-appropriate trail | AC 2: asserts both halves | sufficient |
| 1.3 MUST lowercase + equal folder | zero mismatches corpus-wide | AC 3: asserts the full invariant | sufficient after revision (ISS-006) |
| 1.4 MUST add error rule + document in RUBRIC | fires on two fixture classes, passes conformant, rubric documents id | AC 4: asserts all four | sufficient |
| 1.5 MUST reconcile all 12; changes only per verdict | 12 reports + per-task verdicts + 1:1 mapping + no stray changes | AC 5: asserts all four | sufficient after revision (ISS-004) |
| 1.6 MUST assert end states + idempotence, glob-registered | suite green under discovery + byte-stable regen | AC 6: asserts both | sufficient |
| 1.7 MUST record branch/count/rule/tally | four substrings in top entry | AC 7: asserts all four | sufficient |
§4 — Resolution
Seven findings - three gate-integrity, one measurement-truth, three material - all resolved in the audited revision. Score = 10/10.
Status transition draft -> ready_to_implement is authorised by this verdict per STATUS-REFERENCE.md §1.1 - noting that clauses 1.1 and 1.5 embed the two operator gates inside implementation, per the plan's approval boundary. The two human-acceptance gates in /ship-tasks are unchanged.
End of TASK-IMP-139 audit.