sdlc 1.0 audit — Phase 4 findings and recommended task list
State: open/active · Genre: analysis
Scope: Phase 4 of docs/planning/sdlc-1.0-plan.md — a read-only audit of
solutions/ontological: grade every skill/CLI-op/config-key, code-review the whole tree against
a fixed rubric, reconcile the 2026-07-19 simplification audit, and produce a recommended task
list. 19 sub-agents produced the raw findings under .sdlc/runs/; this document synthesizes
them.
Date: 2026-09-24
Worktree: /Users/sksizer/Developer/dev-sdlc-p4
Headline assessment
Section titled “Headline assessment”solutions/ontological is in good shape for a codebase that has been through three completed
migrations (Python→TypeScript, the apps/sdlc→solutions/ontological move, and the op-substrate
cutover) without a dedicated sweep. Of the 99 findings across the 12 code-quality shards, 9 are
blocking and 31 are major; every one of the 9 blocking findings and a 65% sample of the majors
(20 of 31) were independently re-verified, and every one held up — 29 of 29 sampled
blocking/major findings confirmed (100%), with one ancillary sub-claim (a duplication count
inside an otherwise-sound finding) downgraded from “3x” to “2x” without changing the finding’s
severity.
The dominant theme, recurring in nearly every shard, is stale comments outliving the code they
describe: dead-doc-link error messages (python-runtime.md, never renamed to
typescript-runtime.md), test-file headers still describing a plugin/ directory tree that was
retired months ago, module docs still forwarding to migrate_entities.ts/validate_frontmatter.ts
shims that no longer exist, READMEs listing files (cli/task_cli/index.ts,
cli/task_cli/_common.ts) that were deleted, and a user-facing --help string that states the
wrong exit code. None of these break anything today, but several are actively misleading (a
misconfigured-lease-authority error points a real user at a nonexistent doc; backlog --help
prints exit code 8 for a failure that actually exits 16).
The second theme is “single home” claims that are false. The July 2026 audit’s consolidation
work landed cleanly in most places it touched, but new instances of the same duplication shape
keep appearing: a hand-rolled ancestor-walk in lib/config/load.ts sits beside the very
findAncestor helper that claims to be its “single home”; a misnamed local pyResolve in
migrate-runtime-state silently implements the other, weaker pyResolve contract under the
stronger one’s name; three call sites independently mint the ~19-field task-lease payload; and
lib/util/yaml.ts’s “every caller” claim is false for six production files. The July audit’s own
biggest miss — the dead lib/model/index.ts/corpus/index.ts barrels (PR1 item 6) — is still
unfixed and remains the single largest unaddressed item from that audit.
Third, the surface audit found the codebase’s own execution model is ahead of its wiring in a few
places: sdlc verify changes and pr survey/pr update are exactly the ops the 1.0 plan
describes as core to the phase gate (“judge” and “merges” respectively), fully built and tested,
but nothing dispatches them yet. Genuine dead/unused surface is otherwise rare: 0 of 41 skills and
0 of 47 config keys are a clean “remove,” and only one CLI op (quality.baseline.prune) is a
true orphan.
Surface grading
Section titled “Surface grading”Skills
Section titled “Skills”The skills directory holds 41 skill subdirectories with a SKILL.md (plus README.md and
CLAUDE.md, which are not skills) — the task brief assumed 43; the actual count, confirmed by
directory listing, is 41.
Verdict counts: keep = 12, extras = 28, remove = 0, move-out-to-repo-scripts = 1 (41 total).
| Skill | Core loop? | Verdict | Reason |
|---|---|---|---|
| setup | Yes | keep | Project-bootstrap entry point of the loop. |
| find-verbs | Yes | keep | Sub-step of setup populating verbs.check/verbs.setup. |
| task-new | Yes | keep | Creates the entities the loop executes. |
| task-define | Yes | keep | Fills a task to the implementation-ready contract. |
| task-auto-define | Yes | keep | Automated fallback inside the readiness gate. |
| task-ensure-ready | Yes | keep | The readiness gate at the head of every task-work run. |
| task-work | Yes | keep | The task-execution stage itself. |
| pr-check | Yes | keep | Classifies PR state for orchestrate’s dispatch. |
| pr-respond | Yes | keep | The PR-response stage of the loop. |
| task-close-out | Yes | keep | The close-out stage of the loop. |
| orchestrate | Yes | keep | Ties the whole loop together. |
| spawn-task-pr | Yes (task-work Step 8) | keep | Wired into task-work’s post-mortem follow-up flow. |
| milestone-new | No | extras | Organizes tasks into milestones; not an execution stage. |
| milestones-from-file | No | extras | One-off bulk import from legacy planning docs. |
| milestone-review | No | extras | No wiring evidence either way; keep opt-in. |
| import-planning | No | extras | Onboarding migration, occasional by design. |
| entities-audit | No | extras | The deterministic CLI op (not this skill) runs inside check. |
| entities-migrate | No | extras | Mechanical schema-drift fixer, run occasionally. |
| migrate | No | extras | One-time-per-upgrade sequencer. |
| migrate-runtime-state | No | extras | One-time .claude/ to .sdlc/ mover. |
| docs | No | extras | Regenerates docs artifacts; important but not a loop stage. |
| docs-sweep | No | extras | Large-scale comment sweep; occasional/audit use. |
| bug-finder | No | extras | Whole-codebase bug sweep; occasional, heavyweight. |
| api-enhancement-scan | No | extras | API-surface survey tool; occasional use. |
| explore-codebase | No | extras | Generic exploration methodology; thin usage evidence. |
| capability-map | No | extras | Actively dogfooded capability-graph authoring tool. |
| capability-review | No | extras | Companion verification pass to capability-map. |
| principle-review | No | extras | Governance review over principles; occasional. |
| standard-review | No | extras | Governance review over standards; occasional. |
| standard-new | No | extras | Entity-authoring on-ramp for standards. |
| product-new | No | extras | No cross-references found; entity type exists, skill use unverified. |
| review-todos | No | extras | TODO/FIXME triage; occasional maintenance. |
| session-cleanup | No | extras | Interactive teardown tool; no wiring evidence either way. |
| project-cleanup | No | extras | Repo-wide branch/worktree/task-linkage sweep; occasional. |
| consolidate-task-prs | No | extras | Explicit, occasional cleanup for accumulated single-task PRs. |
| status-dashboard | No | extras | Thin dispatcher to the dashboard verb; convenience. |
| info | No | extras | Diagnostic self-verification tool (“which install won”). |
| backlog-capture | No | extras | Fast idea-capture front door; a parallel input path. |
| backlog-triage | No | extras | Periodic backlog promotion pass. |
| task-review | No | extras | Periodic task-health triage (task-work is the execution stage). |
| update-skill-doc | No | move-out-to-repo-scripts | Repo-specific: hardcodes solutions/ontological/skills/<slug>/SKILL.md; no downstream plugin consumer has skills to author at that path. |
CLI nouns and ops
Section titled “CLI nouns and ops”Verdict counts: keep ≈ 88 ops/groups, extras = 5, remove-or-wire-up = 1, move-out = 0 (revised from
the original ≈ 85 to fold in roadmap.{check,create} and config.get-review-policy, three ops
added to the module manifest after this table was first drafted, and to drop resolve-touchpoints
from the task.{scan-placeholders,...} row below, retired the same way — net +2 rows).
| Noun.op(s) | Verdict | Reason |
|---|---|---|
| capability.{coverage,create,graph,preview-id,update} | keep | Actively-used capability-mapping workflow. |
| reference.{create,preview-id} | keep | Small, used, no issues. |
| standard.{create,preview-id,supersede,update} | keep | Full CRUD lifecycle actually exercised. |
| term.{create,preview-id} | keep | Thin but used (glossary generation). |
| milestone.create | keep | Used by milestone-new / milestones-from-file / import-planning. |
| roadmap.{check,create} | keep | Roadmap authoring plus the roadmap↔milestone↔task cross-reference validator; mirrors milestone’s own create and entities.audit’s “load corpus, walk cross-references, report findings” shape. |
| backlog.{create,capture,update} | keep | Used by backlog-capture / backlog-triage / review-todos. |
| backlog.preview-id | keep | No standalone call site (shares derivation with create); cheap to keep for interface consistency. |
| commit.create | keep | Load-bearing plumbing for the whole commit-message contract. |
| commit.get-schema | keep | Small, real, self-documenting introspection helper. |
| config.get-backlog-policy | keep | Real internal dependency of backlog create. |
| config.get-spawn-policy | keep | Read by task-work Step 8. |
| config.get-review-policy | keep | Mirrors get-spawn-policy/get-backlog-policy: resolves orchestrator.review.command for /sdlc:orchestrate --only review’s Step 2a PR-review dispatch. |
| config.{get-verbs,set-verbs} | keep | Used by find-verbs. |
| config.scaffold | keep | Used by setup. |
| dashboard.{start,stop,list} | extras | Genuinely used and general, but auxiliary to the loop; also carries the --help bug noted below. |
| dev.{history,install,link,off,status,use} | keep | Legitimate operator/dev tooling for developing the CLI itself; not loop-scoped by design. |
| docs.generate | keep | Central, CI/pre-commit-gated, heavily wired. |
| docs.build-subsites | keep | Real but niche; the mechanism is generic even though only this repo exercises it. |
| entities.audit | keep | Part of task-work’s check gate. |
| entities.validate | keep | Heaviest-used op in the group (51+ sites). |
| entities.migrate | keep | Schema-drift maintenance. |
| entities.check-identifiers | keep | Clean general-op / repo-specific-activation split example. |
| entities.get-schema | keep | Introspection (“the schema IS the contract”). |
| gate.worktree-scope | keep | CI-wired (lefthook pre-commit). |
| gate.skill-prose | keep | CI-wired. |
| gate.markdown-fixtures | keep | Wired via sdlc.yaml check verbs and CI. |
| gate.corpus-invocation | keep | Wired via sdlc.yaml check verbs. |
| gate.comment-only | keep | Used by docs-sweep’s verification pass. |
| harness.export | keep | Design-doc-only right now; intentional, not dead. |
| harness.model | keep | Same design-doc cluster. |
| harness.install.claude | keep | Real bootstrap step, doctor-checked. |
| lease.{heartbeat,heartbeat-loop} | keep | Keeps task-work’s/pr-respond’s lease alive. |
| lease.inspect | keep | Used by task-work/orchestrate. |
| lease.list | keep | Sweep/cleanup tooling. |
| lease.reconcile | keep | Heals execution-plane status drift. |
| lease.release | keep | Used by task-ensure-ready. |
| lease.parse-footer | keep | Parses the PR-body lease-binding footer for pr-respond. |
| lease.migrate | extras | One-shot cutover tool, dormant by design (not neglect). |
| lease.op.claim | keep | Generic operation-lease primitive. |
| lease.task.{acquire,archive,claim,fence,reacquire,transition,update-gates} | keep | The task-lifecycle-lease state machine underlying the whole loop. |
| lease.task.sweep | keep | Bulk-archive maintenance op. |
| orchestrate.log-tick | keep | Orchestrate’s own per-tick logging primitive. |
| orchestrate.watch | keep | Deterministic pending-work gate for /loop. |
| plugin.info | keep | The /sdlc:info skill’s whole implementation. |
| plugin.resolve | keep | Used by the info skill. |
| plugin.install-permissions | keep | Seeds the project Claude-Code allowlist. |
| pr.classify | keep | The classifier orchestrate dispatches on — but flagged plumbing-only/--advanced despite being the most-used op (help-text inversion, see below). |
| pr.review | keep | Real, human-driven review session; outside the automated loop by nature. |
| pr.survey | extras | Built, tested, but not wired into orchestrate or any skill — a planned core-loop piece per the 1.0 plan. |
| pr.update | extras | Same status as survey; matched pair. |
| project.setup | keep | The “setup” stage of the core loop. |
| project.doctor | keep | Setup-adjacent. |
| project.detect-setup | keep | Used by find-verbs. |
| project.{preflight-worktree,teardown-worktree} | keep | Used broadly across worktree-mediated flows. |
| project.cleanup | keep | Maintenance, run on demand. |
| project.scan.{candidates,comments,todos} | keep | Planning-ingestion helpers (import-planning / docs-sweep / review-todos). |
| quality.detect | keep | Setup-adjacent. |
| quality.run | keep | The single most central op in the CLI — the deterministic check step and CI. |
| quality.baseline.{capture,diff} | keep | Used by task-work’s baseline gating. |
| quality.baseline.prune | remove or wire it | Only clear orphan: baselines accumulate unbounded under .sdlc/, nothing prunes them. |
| repo.checkout | keep | Wrapped by the generated sdlc-repo-checkout shell function. |
| repo.{trust,untrust} | keep | task-work’s consent gate. |
| report.{get-schema,render} | keep | Review-report rendering, “schema is the contract” pattern. |
| shell.init | keep | Implements sdlc-cd/sdlc-at/sdlc-pr-review/sdlc-repo-checkout. |
| site.build | keep | Deploy-time site build. |
| verify.changes | extras | Documented as core to the phase gate’s “judge” step, but no skill invokes it yet — the clearest planned-but-unwired gap in the surface. |
| task.create | keep | Task authoring. |
| task.next | keep | The dispatch-order selector orchestrate/task-work both use. |
| task.inflight | keep | Categorizes in-flight tasks against per-project limits. |
| task.probe-state | keep | Pre-flight worktree/branch/PR/status probe. |
| task.resolve | keep | Used by close-out/ensure-ready/review. |
| task.gap-report | keep | Deliberate composite over the scan/parse/check ops below. |
| task.{scan-placeholders,parse-touchpoints,check-claims} | keep | Readiness-gate internals, independently callable and composed. (A fourth op, resolve-touchpoints, existed when this table was drafted; it was retired afterward — Files-to-touch became Areas — and task/schema.ts now says so in its own comment. gap-report.ts’s composite was updated cleanly, so this was a doc-accuracy staleness only, not a functional gap.) |
| task.close-commit | keep | The close-out step. |
| task.lint-state-origin | keep | CI-wired commit gate. |
| task.list-unmerged | keep | Dedup / PR-branch task-file detection. |
| task.preview-id | keep | Used by task-new / import-planning / review-todos. |
| task.update | keep | Used by task-new / task-auto-define. |
Two help-text bugs surfaced by the same audit (see the Fix list): sdlc dashboard --help prints
an empty “Registry-generated ops ()” summary even without --advanced, and pr classify is
hidden behind --advanced while pr survey/pr update show as primary — the inverse of actual
usage.
Config keys
Section titled “Config keys”Verdict counts: keep = 38, extras = 8, move-out-to-repo-scripts (candidate) = 1, remove = 0 (47
total; expanding each (N subkeys)/{...} annotation as N keys, the same convention extras
already used — the original count of 43 missed that expansion on two keep rows
(pr_review.prompt.{mode,text} and verify.{...}’s 9 keys) and omitted a 47th key,
orchestrator.review.command, entirely). Every key in SdlcConfigSchema, including that 47th
key, has at least one real reader; no dead config surface was found.
| Key (dotted path) | Verdict | Reason |
|---|---|---|
verbs | keep | The one place lifecycle shell commands live. |
orchestrator.max_implementations | keep | Hard dispatch cap read by task inflight. |
orchestrator.max_awaiting_review | keep | Informational review-queue ceiling. |
orchestrator.review.command | keep | Validated (must contain {pr}) dispatch command for /sdlc:orchestrate --only review’s Step 2a, one PR-review sub-agent per open PR; defaults to the pr-tools plugin’s review command. Load-bearing for the opt-in review phase. |
pr_check.author_comments | keep | Drives the NEEDS-RESPONSE verdict. |
pr_check.ignored_authors | keep | Bot-noise filter feeding the same classify path. |
pr_update.author | keep | Scopes pr survey/pr update. |
pr_update.include_drafts | keep | Same survey scope. |
pr_update.strategy | keep | Rebase/merge decision for restacking. |
pr_update.overrides | keep | Per-PR strategy override, first-match. |
pr_update.guards.unpushed_local | keep | Non-negotiable data-safety guard. |
pr_update.guards.reviewed | keep | Preference guard, avoids outdating review threads. |
pr_update.guards.max_rebase_commits | keep | Preference guard, falls back to merge. |
pr_update.lockfile_install | keep | Lockfile-conflict rebuild verb. |
pr_update.resolvers | keep | Project codegen conflict resolution, first-match. |
pr_update.verify | keep | Gates whether verbs.check reruns before push. |
task.execution.spawn_from_post_mortem.* (5 subkeys) | extras | Real feature, but an optional task-work Step 8 side effect, not the setup-task-PR spine. |
backlog.capture.* (3 subkeys) | extras | A separate idea-capture flow, not part of the core loop. |
lease_authority | keep | Required for every lease op; task-work’s coordination depends on it. |
docs_site | keep | Real, well-used docs-site generation; auxiliary, not core. |
plugin_source | move-out-to-repo-scripts (candidate) | Only meaningful for a checkout that itself hosts SDLC’s own source (today, only sksizer/dev). |
paths | keep | Token map for repos:/checkout.layout. |
repos | keep | Needed for cross-repo pr survey/update, project cleanup. |
checkout.layout | keep | repo checkout destination template. |
checkout.protocol | keep | Clone protocol for repo checkout. |
host.default | keep | Session-hosting fallback for pr review and other interactive ops. |
pr_review.engine | keep | Interactive review agent, phase-gate step 3. |
pr_review.host | keep | Per-feature host override. |
pr_review.untrusted | keep | Fork-trust policy for the review worktree. |
pr_review.setup | keep | Whether the setup verb runs before the review session. |
pr_review.prompt.{mode,text} | keep | Review-brief composition. |
verify.{engine,model,concurrency,blocking,severity_floor,exclude,max_prompt_bytes,max_files_per_job,timeout_ms} | keep | verify changes = the “judge” step of the phase gate. |
The scaffold (lib/config/scaffold.ts) is fully schema-derived — every value, default, and
comment projects from SdlcConfigSchema’s own .describe()/.default() — so it cannot drift
from the schema by construction. The July 2026 finding that stale .describe() prose named
deleted Python scripts is confirmed fixed here (no .py reference remains); a related, narrower
staleness in one .describe() string survives and is tracked in the Fix list below (docs_site’s
list-ops.ts claim).
Code-quality review
Section titled “Code-quality review”99 findings total across 12 shards: 9 blocking, 31 major, 59 minor. All 9 blocking findings and a 65% sample of majors were independently verified with zero false positives (see Verification methodology).
Lease + orchestrator
Section titled “Lease + orchestrator”Blocking: 1 (fixed as of the current head — see note). Major: 3. Minor: 4.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
lib/services/lease/ops/_common.ts:277-278 | Blocking (fixed) | Misconfigured-lease-authority error message pointed users at conventions/python-runtime.md, which doesn’t exist (renamed to typescript-runtime.md). | Already fixed as of the current head: an origin/main merge folded into this branch (commit d4065007c/68f344d32, “fix: remove stale reference to nonexistent python-runtime.md convention doc”) before this audit’s own last commit landed. The message now points at lib/services/lease/README.md; git grep python-runtime over solutions/ontological returns nothing. |
lib/services/lease/runtime.ts:366-390, migration.ts:154-199, ops/task/claim.ts:88-109 | Major | Three sites independently hand-spell the ~19-field TaskLifecycleLease initial-claim payload; no canonical constructor exists. | Extract a shared buildInitialTaskLeasePayload(opts) used by all three. |
lib/services/lease/ops/task/transition.ts:265-355 vs runtime.ts:472-526 | Major | The op reimplements transitionLease()’s whole fetch/mutate/CAS algorithm instead of calling it; only the phase-classification Sets are shared. | Call transitionLease(...) and layer the op’s extra expiry pre-check on top. |
lib/services/lease/reconcile.ts:1396-1526 (loadReconcileState) | Major | ~130-line function mixes ref-diffing, authority fetch, a 4-way ref-namespace categorization loop, and task/PR observation. | Split the ref-categorization loop into a categorizeRefs helper. |
Minors:
lease/heartbeat-service.ts:147— comment cites a nonexistentlease_heartbeat_loop.ts.lease/guard.ts:34—CheckNamespaceConflictOptionsexported but only used internally.lease/ops/task/sweep.ts:76-81vsops/_common.ts:64-73— twotaskIdFromReffunctions with different contracts (throw vs. null) share a name; risks a future edit assuming parity.lease/ops/op/claim.ts:117-135vsops/task/claim.ts:111-129— identical validate/build/CAS try-catch skeleton copy-pasted between the two claim handlers.
Docs + design-tokens
Section titled “Docs + design-tokens”Blocking: 1. Major: 1. Minor: 2. (The shard’s own header table stated Major: 2; only one finding in the body is actually tagged major — corrected here.)
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
7 test files incl. docs/tests/site_ownership.test.ts:30 and 6 siblings | Blocking | Comments describe a plugin/... directory tree retired by the repo restructure; segment counts are now wrong too (5 vs. the actual 6). | Update all 7 comments to the solutions/ontological/... layout with correct segment counts. |
lib/services/docs/generate.ts (852 lines) | Major | File owns 8 distinct concerns (status bucketing, per-section assembly for 8 entity types, glossary/references, rendering, artifact registry, 2 drift-check paths); site/reference.ts already documents the precedent for splitting a file at this size. | Split per the site/reference.ts precedent; extract the duplicated titleOf+sort block (lines 472-474, 513-515) into a shared sortByTitle. |
Minors:
docs/generate.ts:472-474,513-515— duplicatedtitleOf+sort block (companion to the major above, independently actionable).design-tokens/project.ts:144-152—projectSeedSethas zero call sites/tests.
Gate + PR
Section titled “Gate + PR”Blocking: 1. Major: 1. Minor: 2. (The shard’s header table stated Major: 2; only one body finding is tagged major — corrected here.)
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
gate/ops/_skill_prose_contract.ts:4 | Blocking | Header says “14 covered skills”; the registry has 16, and the sibling test pins 16. | Update the comment to 16 (or phrase it to avoid future drift). |
pr/update/resolvers.ts:38-39 | Major | ResolverKind type is dead (zero importers) and inconsistent with PathPlan.kind ('rerere' vs. 'unclaimed'). | Delete ResolverKind, or reconcile it with PathPlan['kind'] and wire it in. |
Minors:
gate/ops/worktree-scope.ts:135— comment implies a mirrored standalone script that doesn’t exist.pr/ops/survey.ts:436-438andpr/update/tui.tsx:75-77— identical hand-rolledpad()reimplementsString.prototype.padEnd.
Dashboard + project
Section titled “Dashboard + project”Blocking: 1. Major: 4. Minor: 6.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
lib/services/dashboard/server.ts:1499-1510,1607 | Blocking | tcpProbe is dead (superseded by dashboardHealthy), kept alive by a void tcpProbe silencer — the exact defect shape the July audit flagged for this file, recurring under a new symbol. | Delete tcpProbe and the silencer line. |
lib/services/dashboard/project-registry.ts:192-198 | Major | projectRegistry() singleton getter and its backing shared variable are fully dead; the real caller uses createProjectRegistry() directly. | Delete both, or wire makeApp’s default parameter to use it. |
dashboard-service.ts:47-89 vs dashboard-service-main.ts:23-62 | Major | Near-identical ~40-line CLI arg parsers duplicated across two files. | Extract one shared parseDashboardArgs(argv, extraFlags?). |
project/ops/scan-candidates.ts:105-280 | Major | A full hand-rolled .gitignore glob-to-regex compiler plus Python-mtime formatting (~150 lines) lives inline at the op layer, inverting the stated lib/util vs. lib/services layering. | Move the gitignore-glob compiler and mtime helpers into lib/util/. |
project/ops/setup.ts:139-159 (readLeaseAuthority) | Major | Hand-rolls what @lib/config’s resolveAuthority already does; dashboard/server.ts in the same shard already calls the canonical one. | Replace with resolveAuthority(null, resolvedRoot). |
Minors:
dashboard/server.ts:293-334—BROWSABLE_ENTITY_TYPEScomment claims sole source of truth, but the desktop app maintains an independent mirrored list with no compile-time link.dashboard/server.ts(several lines) — 7 symbols exported with zero external importers.project/ops/scan-candidates.ts:10-11— comment claims byte-compatibility with a deleted legacy script.project/ops/setup.ts:207— ad hoc Python-style boolean formatting duplicatescleanup/index.ts’s unexportedpyBool.project/ops/_gitignore.ts:40-59— two exported helpers used only internally.project/cleanup/index.ts:67-70,561-570— two exported interfaces with zero importers by name.
Misc services (harness, plugin, host, verify, quality, repo, commit, config, dev, git, report, shell)
Section titled “Misc services (harness, plugin, host, verify, quality, repo, commit, config, dev, git, report, shell)”Blocking: 1. Major: 4. Minor: 6. (The shard’s own summary stated Major: 5; only 4 findings are actually tagged major in the body — a bookkeeping slip in the source file, corrected here and noted again in Verification methodology.)
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
services/config/verb-list.ts:59-65 | Blocking | SDLC_YAML_HEADER doc comment claims byte-identity with a _SDLC_YAML_HEADER symbol that doesn’t exist; the real sdlc project setup header (configScaffoldYaml) is a different, longer comment. | Share one header constant, or correct the comment. |
quality/ops/run.ts:352-367 vs quality/ops/baseline/diff.ts:99-116 | Major | Both independently implement “compute pre-existing findings” — logic baseline.ts claims to canonically own. | Add preExistingFindings(current, baseline) to baseline.ts; call it from both. |
quality/ops/run.ts:193-397 (handler) | Major | ~200-line handler does 6+ distinct things, mixing execution with baseline-gating render logic. | Extract the baseline-gating block into an applyBaselineGate helper. |
verify/ops/changes.ts (whole file) | Major | No test file anywhere covers this op — the riskiest file in the shard (severity-floor gating, exit-code computation, the “every judgement failed” error path, HTML report generation). | Add unit/CLI tests for the blocking/non-blocking exit paths and the MODEL_ERROR path. |
plugin/info-report.ts:18-25 vs plugin/ops/resolve.ts:23-30 | Major | Both declare an identical private loadJson; both hand-parse the same on-disk plugin-registry shape independently. | Extract a shared readPluginRegistry/loadJson into plugin/registry.ts. |
Minors:
config/tests/verbs_ops.test.ts:12— repeats the same false_SDLC_YAML_HEADERreference.quality/ops/run.ts:337-340—BaselineEntryinterface redeclared inline instead of imported frombaseline.ts.host/hosts/{cmux,orca,terminal}.ts— identical 6-linesession()block copy-pasted 3 times.harness/ops/install-claude.ts:306-411— 105-line handler, mildly under-decomposed.repo/ops/{trust,untrust}.ts— identicaltargetRoot()helper declared in both files.verify/ops/changes.ts(whole file) — mixes CLI rendering, pure helpers, op handler, and HTML-report assembly in one 534-line file.
Entities: task
Section titled “Entities: task”Blocking: 0. Major: 2. Minor: 6.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
entities/task/ops/inflight.ts:26,161 | Major | existsSync imported then only referenced via void existsSync; the adjacent comment describes a .git-file-or-dir check that is never actually implemented. | Implement the described check, or delete the dead import and stale comment. |
entities/task/ops/lint-state-origin.ts:58-60 | Major | User-facing stderr message hardcodes a dead date-slug doc path; the file was migrated to T-SIHV-.... | Update the literal string to the current path. |
Minors:
lint-state-origin.ts:9,_lint_state_origin_core.ts:6,69, its test — stale date-slug wikilink (companion to the major above).entities/task/ops/parse-touchpoints.ts:440—export type { Section }has no importer.entities/task/claims/paths.ts:177andclaims/quantifiers.ts:125— unused default exports.entities/task/migrations/errors.ts—MigrationErrorbyte-identical to the capability entity’s version (see also entities: other, below).entities/task/ops/next.ts:72-92—IMPACT_MISSING = -1used only via double-negation; confusing sign, correct logic.
Entities: other (backlog, capability, decision, driver, milestone, principle, product, reference, standard, term, corpus)
Section titled “Entities: other (backlog, capability, decision, driver, milestone, principle, product, reference, standard, term, corpus)”Blocking: 0. Major: 1. Minor: 6.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
principle/reports/review/schema.ts:30-89 vs standard/reports/review/schema.ts:26-87 | Major | findingSeverity/finding/proseIssue/*ReviewReport are ~95% identical between the two files, differing only in field-name prefixes; a structurally different third schema (task/reports/review/schema.ts) was initially miscited as a third copy — see the Verification note below. | Extract a shared reviewFindingSchemas(entityNoun) factory in lib/services/report/schema.ts. |
Minors:
capability/migrations/errors.ts:1-15—MigrationErrorduplicated with the task entity’s version (same underlying issue as the task-shard minor above; only one shared fix needed).entities/_common.ts:144-146— comment cites a nonexistentlib/model/tests/entity.test.tspath (real file islib/model/entity.test.ts).milestone/schema.ts:30—MILESTONE_VERSION_PATTERNexported with no importer.principle/schema.ts:25—PRINCIPLE_CATEGORY_PATTERNexported with no importer.capability/ops/coverage.ts:162-281— 119-linebuildCapabilityCoveragespans 5 phases.capability/ops/graph.ts:93-243— 150-linebuildCapabilityGraphspans 5 phases.
Model root + ops
Section titled “Model root + ops”Blocking: 0. Major: 3. Minor: 8.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
lib/model/index.ts (27 lines) | Major | Dead barrel — zero importers via from '@lib/model' anywhere in the repo; every real consumer imports deeper paths. This is PR1 item 6 from the July audit, still unfixed and the single biggest gap. | Delete the barrel (and cascading dead exports — see minors). |
lib/model/ops/migrate.ts:2-3,14-18 and ops/audit.ts:20-23 | Major | Module docs describe a migrate_entities.ts CLI entry point that forwards to runMigrate; no such file exists anywhere — the logic now lives inline in migrate.ts’s own handler. | Rewrite both doc comments to describe the current architecture. |
lib/model/ops/validate.ts:18-31,82-89 | Major | Comments say a validate_frontmatter.ts/validate_base.ts shim “keeps its own copy until T-YBKU deletes it” — that task is closed/done and the shim files don’t exist. | Rewrite to past tense, or drop the historical framing. |
Minors:
lib/model/read.ts:189-191(frontmatterOf) — dead outside the dead barrel above.lib/model/corpus/index.ts:9—readFrontmatterre-export has no real caller.lib/model/index.ts:1-6— header cites a nonexistent__init__.pyPython source.lib/model/entity.ts:284-305(hydrateFrontmatter/HydrateResult) — full implementation, no production caller, no self-documenting disclaimer (unlike its siblingscaffold).lib/model/ops/_preview_id.ts:149— useslocaleCompareinstead of the codebase’s locale-independentcmpStrconvention.lib/model/ops/validate.ts:554-691— the one op in this directory that inlines its engine directly in thedefineOphandler instead of a standalonerun*()function.lib/model/ops/migrate.ts:346-484(runMigrate) — ~140-line multi-responsibility function.lib/model/entity.ts:216-267(scaffold) — dead in production, but already self-documented as intentional test-only surface; informational only.
Util + config
Section titled “Util + config”Blocking: 4. Major: 7. Minor: 4.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
lib/config/load.ts:613-623 (resolveProjectRoot) | Blocking | Hand-rolls the exact ancestor-walk loop that lib/util/paths.ts’s findAncestor claims as its “single home,” despite load.ts already importing other @lib/util modules. | findAncestor(start, dir => existsSync(join(dir, 'sdlc.yaml'))) ?? resolve(start). |
skills/migrate-runtime-state/migrate_runtime_state.ts:64-74 | Blocking | Local pyResolve is byte-for-byte paths.ts’s realResolve (no walk-up) — but collides in name with paths.ts’s own, differently-behaving pyResolve (which does walk up). | Delete the local copy; import realResolve (or pyResolve if walk-up is actually wanted). |
lib/util/yaml.ts:1-8 | Blocking | ”Every caller imports parse… from here” is false: 6 production files import from npm yaml directly. | Migrate the 5 one-line-swap production sites; add a parseDocument/Document re-export for verb-list.ts’s genuinely different need. |
lib/config/sdlc_yaml.ts:19-21 | Blocking | Cites task T-MBOK as a pending future landing for the yaml chokepoint; T-MBOK is closed/done and the chokepoint already exists. | Swap the import to @lib/util/yaml; delete the stale note. |
lib/config/merge.ts:18-20 | Major | Private isPlainObject byte-identical to lib/util/guards.ts’s exported isRecord; guards.ts’s own header names lib/config a sanctioned importer. | Import isRecord; delete isPlainObject. |
skills/task-ensure-ready/ensure_ready_mutate.ts:185-193 | Major | Private nowIsoUtc reimplements rfc3339(nowUtc()), used to stamp readiness_verified_at. | import { rfc3339, nowUtc } from '@lib/util/date'. |
lib/services/verify/ops/changes.ts:459 | Major | Bypasses todayUtc() with an inline new Date().toISOString().slice(0, 10). | date: todayUtc(). |
lib/util/strings.ts singularize vs lib/util/naming.ts pluralize | Major | Independent, non-inverse implementations of the same domain; pluralize('class') → 'classes', singularize('classes') → 'classe' (wrong). Currently latent since no entity type name hits the gap. | Share an irregular-noun table, or add a round-trip property test. |
lib/services/lease/tree.ts:34-42 (nowCommitDate) | Major | Hand-derives the git commit-date format via regex instead of composing rfc3339, while a sibling file in the same subsystem (runtime.ts:769) already does it the composed way. | rfc3339(nowUtc()).replace(/Z$/, '+0000'). |
4 sites (list-unmerged.ts:227, scan-candidates.ts:400, skill-prose.ts:76, summarize_dedup_telemetry.ts:240) | Major | Each hand-rolls the exact cmpStr-shaped ternary comparator instead of importing cmpStr. | Import cmpStr from @lib/util/strings at all 4 sites. |
lib/config/load.ts:365-372 (docs_site .describe()) | Major | Claims <dir>/scripts/list-ops.ts resolves beneath docs_site; it actually resolves from the plugin’s own tree, independent of docs_site — and this exact string leaks into every consumer’s generated sdlc.yaml via the scaffold. | Drop or rewrite the list-ops.ts clause in the .describe() string. |
Minors:
lib/util/claude-home.ts—claudeHome()exported but only ever called internally.experiences/system-graph/app/lib/pattern.ts:95— inlineescapeRegExpreimplementation, but outsidesolutions/ontological’s own dependency graph, so not a violation of its claim.products/system-graph/server/utils/project-root.ts:22-30— same ancestor-walk pattern asfindAncestor, same out-of-package caveat as above.lib/services/harness/ops/install-claude.ts:352— ad hoc millisecond-precision ISO timestamp, not routed throughdate.ts(low risk, not byte-compared anywhere).
Blocking: 0. Major: 4. Minor: 6.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
cli/task_cli/README.md:17-31 | Major | ”Layout” block claims index.ts/_common.ts files and build_task_subtree()/dispatch_task() functions that don’t exist anywhere in the repo. | Rewrite to reflect the actual shape (README + tests/) and point at entities/task/ops/next.ts / registry_adapter.ts. |
cli/backlog_cli/_common.ts:29 and index.ts:61-62 | Major | Both say MODEL_ERROR exits with code 8; the actual value (via exitCodeFor) is 16. The “lease owns 2-7” comment is also wrong (lease is 10-13). User-visible via sdlc backlog --help. | Correct both to 16; fix or remove the numeric-band claim. |
cli/tests/lease_dispatch.test.ts:23,366,372,382,394,438 | Major | 5 raw child_process.spawnSync calls, no @sdlc:ignore-spawn-style note, despite the same file already using runCli for other tests. | Replace all 5 with runCli/runCapture from @lib/tests/_cli_harness.ts. |
cli/backlog_cli/tests/create.test.ts:9,115 | Major | Raw spawnSync('ls', ...) duplicates an already-imported readdirSync used for the identical purpose 400 lines later in the same file. | Replace with the existing readdirSync call. |
Minors:
cli/registry_adapter.ts:113-120vscli/_common.ts:35-42— byte-identicaljsonlSortReplacer/sortedKeysReplacer.cli/sdlc.ts:407-408— dead re-exports with no importer.cli/registry_adapter.ts:699— deadexitCodeForre-export.cli/backlog_cli/{create,capture}.ts,_common.ts, 2 test files — 5 stale “mirrors the Python tier” comments.cli/backlog_cli/README.md:11-22— layout block disagrees with actual test-file placement.cli/task_cli/tests/dispatch.test.tsandcli/backlog_cli/tests/dispatch.test.ts— duplicated ad hocBun.spawncapture helpers instead of the shared_cli_harness.ts.
Skills + scripts (+ conventions)
Section titled “Skills + scripts (+ conventions)”Blocking: 0. Major: 1. Minor: 8.
| File:line | Severity | Description | Suggested fix |
|---|---|---|---|
skills/task-ensure-ready/ensure_ready_mutate.ts:723-963 (applyVerdict) | Major | ~240-line function fuses flag validation, lease discovery, the --commit-on flow, the standalone --commit flow, and the no-commit passthrough. | Extract the --commit-on and --commit arms into named helpers, matching the file’s own existing decomposition style. |
Minors:
skills/migrate-runtime-state/migrate_runtime_state.ts:64-74— samepyResolve/realResolvecollision as the util-config blocking finding B2 above (one shared fix).skills/task-ensure-ready/scan_corpus_assumptions.ts(7 lines) — stale comments citing a nonexistentscan_placeholders.ts.scan_corpus_assumptions.ts:247-282vsskills/task-work/dedup_search.ts:442-531— two independent hand-rolled Python-json.dumps-compatible encoders.skills/task-work/dedup_search.ts:513-515— dead/redundant identical-branch conditional.skills/task-work/summarize_dedup_telemetry.ts:26-28—rjustduplicated verbatim fromlib/services/project/ops/setup.ts:66-68.scripts/compiled/bootstrap.ts:62-110— unmarked raw spawns (no@sdlc:ignore-spawn) plus an inaccurate “build tooling, not runtime” header claim, though it ships inside the compiled binary.scripts/build-binary.ts:80-85vsscripts/build-npm-wrapper.ts:103-108— identicalrun()helper duplicated between two files that already know about each other.conventions/schema-bump-checklist.md:7-8— cites nonexistentaudit_entities.ts/migrate_entities.tsscripts instead of the actualsdlc entities audit/migrateCLI ops.
Workspace deps
Section titled “Workspace deps”Blocking: 0. Major: 0. Minor: 1.
All 14 packages/ts/<name> workspace dependencies consumed by solutions/ontological are
actively imported with no unused packages, no stale commits, and no hand-rolled child_process/gh
argv bypassing the command seam.
lib/util/git.ts:70-127(isLinkedWorktree,listWorktreeBasenames) — partially overlaps@sksizer/easy-git’s own worktree primitives (mainCheckout(),worktrees()); the filesystem scan can silently disagree with git’s own registry. Derive from easy-git, or document the git-binary-free rationale explicitly.
Prior-audit reconciliation
Section titled “Prior-audit reconciliation”Reconciling docs/planning/notes/N-UAG5-2026-07-19-sdlc-simplification-audit.md’s 11-PR stack
against the current tree. Counts below are row-based (a companion sub-item with its own status gets
its own row; mixed-status rows are counted under their primary/leading status).
Summary: Fixed = 79, Still present = 13, Obsolete = 4 (96 itemized entries total across both
ranges — expanding PR8’s 1-4,4a-4e,6-8 consistently with the rest of this table’s ranges gives
12 items, not 8, which moves Fixed from 78 to 79 and the total from 95 to 96).
PR1-PR6
Section titled “PR1-PR6”| PR | Item | Description | Status | Evidence |
|---|---|---|---|---|
| 1 | 1 | Delete lib/services/quality/run-checks.ts + dead exports | Fixed | File and all named symbols absent. |
| 1 | 1a | Reword ops/run.ts’s “mirrored from the script” comment | Still present | ops/run.ts:44 still reads it, though the script is gone. |
| 1 | 1b | Fix 3 task files’ stale run-checks.ts touchpoint rows | Still present | T-YF4K/T-BCNP/T-BQRU still cite it. |
| 1 | 2 | Delete lib/util/schema_patterns.ts + test | Fixed | File and test absent; zero references. |
| 1 | 2a | Backlog superRefine reject-branch coverage | Fixed | Both update.test.ts and create.test.ts assert reject cases. |
| 1 | 2b | Note arrayElement as intentionally orphaned | Still present | Function exists, no such note added. |
| 1 | 3 | Delete verify_prs_against_pr.ts + SKILL.md fix | Fixed | File/test absent; SKILL.md uses sdlc task close-commit. |
| 1 | 4 | Delete lease/canonical_json_cli.ts | Fixed | File absent. |
| 1 | 4a | Fix tree.ts header’s “CLI wrapper” rationale | Still present | Still cites a CLI wrapper, not orchestrator/ops/watch.ts. |
| 1 | 5 | Delete cli/task_cli/_common.ts | Fixed | File absent. |
| 1 | 5a | Fix task_cli/README.md’s stale Layout block | Still present | Worse than anticipated — index.ts also now gone. |
| 1 | 6 | Delete lib/model/index.ts + corpus/index.ts barrels | Still present | Both barrels still exist — the single biggest unfixed item (see Headline). |
| 2 | 1-9, 11, 13 | Delete dead exports/branches in entity.ts, ops/audit.ts, identifier.ts, config/schema.ts, cli/_common.ts, dashboard/server.ts, registry_adapter.ts, ops/validate.ts, wikilinks.ts/markdown_extract.ts, task ops/* tails, _skill_prose_contract.ts | Fixed | All confirmed absent/corrected by direct grep. |
| 2 | 1a | Refresh RF-0004-json-schema-2020-12.md fully | Still present (partial) | Notes section says the $ref resolver “was retired,” but the Summary above it still asserts it as present-tense fact; stale apps/sdlc path too. |
| 2 | 6a | tcpProbe current status | Still present | Recurs (see Dashboard + project shard). |
| 2 | 6b | void existsSync in task/ops/inflight.ts | Still present | Recurs (see Entities: task shard). |
| 2 | 6c,6d | void parsePath / void inline/void topScore | Fixed | All three symbols/silencers gone entirely. |
| 2 | 10 | git/easy.ts dead-export cleanup | Obsolete | File no longer exists — superseded by the @sksizer/easy-git extraction. |
| 2 | 12 | Un-export 7 cleanup/index.ts pipeline stages | Fixed (2 of 7 named) | Confirmed unexported where checked; 7 intended-public exports correctly kept. |
| 2 | 12a | Un-export 5 more functions + PRInfo | Obsolete | None exist anymore — the pipeline was restructured around gatherAndClassify. |
| 2 | 14 | Fix 4 Python-script .describe() references | Fixed (2) / Obsolete (2) | orchestrator/lease_authority fixed; quality_checks/worktree_init fields no longer exist (superseded by a unified verbs: field). |
| 3 | 1-7 | Add lib/util primitives (guards.ts, py.ts, escapeRegExp, fs.ts additions, stringField, frontmatter fences, worktreeDir) | Fixed | All 7 present and tested; py.ts landed as diagnostics.ts instead (equivalent semantics, different name). |
| 4 | 1-5 | Adopt isFile/isDir/escapeRegExp at named sites; prune baseline JSON | Fixed (large majority) | A few named files (append_pr_url.ts, old frontmatter.ts, detect-runners.ts) are obsolete citations — superseded by later restructuring, not unfixed. |
| 5 | 1,2,4 | Adopt rfc3339/posix; delete dashboard/server.ts’s private parseRfc3339 | Fixed | Confirmed at all named sites; documented exceptions (lease/tree.ts, lease/runtime.ts) correctly left alone. |
| 5 | 3 | Adopt cmpStr at ~12 sort sites | Fixed (11 of 12) | One remaining inline comparator at scan-candidates.ts:400 (recurs as util-config M6, above). |
| 6 | 1-3,5 | Adopt typeName/repr/isRecord; collapse v3-to-v4/v4-to-v5 via stampOnlyMigration | Fixed | All confirmed; py.ts naming diverged as noted in PR3. |
| 6 | 4 | Adopt pyRepr at 2 sites; leave v2-to-v3.ts’s pyReprStr alone | Fixed, with one divergence | pyReprStr was folded into the shared repr() anyway — the audit said not to; no evidence of resulting breakage. |
| 6 | 6 | Fold MigrationError (task + capability) | Still present | Audit itself marked this optional; recurs in this audit as an entities-task/entities-other minor. |
PR7-PR11
Section titled “PR7-PR11”| PR | Item | Description | Status | Evidence |
|---|---|---|---|---|
| 7 | 1,4,5,6,7 | Route frontmatter parsing through parseFrontmatterResult/splitFrontmatter; relocate task-specific prs: helpers out of lib/util | Fixed | All confirmed at the named sites. |
| 7 | 2 | Adopt fence-preserving helpers at _update.ts+migrate.ts | Fixed (migrate.ts) / Obsolete (_update.ts) | _update.ts moved to a span-preserving editFrontmatterFields engine, superseding the ask. |
| 7 | 3 | Route writePrsFrontmatter through dumpFrontmatter; fix parity bugs | Obsolete | Function relocated to entities/task/prs.ts, now uses editFrontmatterFields — sidesteps the whole question. |
| 8 | 1-4,4a-4e,6-8 | Converge on _probe_core.ts helpers, worktreeDir/worktreeDirRel, @lib/util/location’s globMatches, Git instance threading (5 sub-items), scanEntities-based loadTasks, _table_cells.ts | Fixed | All confirmed at named sites, including the easy-git package extraction the audit anticipated. |
| 8 | 5 | Delete dead makeRunFn/_gitRunner; thread Git at 3 sites | Obsolete | All git-spawning code was extracted wholesale into a new @sksizer/repo-cleaner package. |
| 9 | 1-7 | Promote wikilink/id-pattern factories, requiredWhen, RESULT_PATTERN_BY_STATUS; fix stale headers | Fixed | All 7 confirmed. |
| 10 | 1-4,6a,6b,6c | Extract leaseTarget, expiresAt, freshOwnerOrNull; add missing LeaseConflict arm; export OWNER_KIND/OPERATION_STATE | Fixed | All confirmed; the missing-arm fix (item 4) is a real prior exit-code bug, now covered by a test. |
| 10 | 5 | Single-source lease phase sets | Fixed | runtime.ts exports both sets; transition.ts imports them; the intentionally-separate TRANSITION_PHASES enum correctly remains distinct. |
| 11 | 1,2,3,5 | Replace hand-rolled site.ts frontmatter parsing; extract site/reference.ts; collapse escapeFmString; extract site/write.ts | Fixed | All confirmed, including the per-skill catch-and-continue behavior the audit prescribed. |
| 11 | 4 | Unify the two ## Purpose extractors via sectionBody | Still present | sectionBody exists but neither extractor uses it; audit itself flagged this as low-value. |
| 11 | 6 | Collapse duplicated recursive .md walk (rglobMd vs listMdFilesRecursive) | Still present | Both still exist independently in audit.ts and site.ts. |
| 11 | 7 | Fold adrSection’s inline bucketing into splitSection | Still present | Audit itself deprioritized this; unfixed as expected. |
The most consequential still-present item is PR1 item 6 — the lib/model/index.ts and
corpus/index.ts dead barrels — which never landed across two follow-up PR ranges and remains the
single largest gap in the reconciliation (see Prune task list, below).
PR3’s premise diverged, but the underlying problem was still fixed. The audit prescribed a new
lib/util/py.ts exporting pyTypeName/pyRepr. That file was never created; instead
lib/util/diagnostics.ts (with typeName/repr) became the module every prospective call site
actually adopted, evidently as part of a broader move away from “Python-port” naming. The
duplication problem PR3 targeted — 8 independent shim copies — is fully resolved either way; only
the literal file/function name differs from the prescription.
Recommended task list
Section titled “Recommended task list”Grouped by category, with the target phase derived from docs/planning/sdlc-1.0-plan.md’s phase
list. Pure dead-code/duplication/stale-comment cleanup inside solutions/ontological with no
dependency on later-phase work defaults to Phase 13 (the plan defers all audit pruning/refactor
execution there, alongside the TUI). Two items complete wiring that Phase 2 itself defines
(judge/pr-update workflow steps) and are mapped there instead. No task in this list concerns
publishing/npm/marketplace-sdlc mechanics, so none map to Phase 14.
| Task | Areas | Target phase |
|---|---|---|
Delete the dead lib/model/index.ts barrel and its cascade (frontmatterOf, corpus/index.ts’s dead readFrontmatter re-export) | lib/model/ | Phase 13 |
Delete dead code in services: tcpProbe (dashboard/server.ts), projectRegistry() singleton (dashboard/project-registry.ts), the void existsSync lint-silencer in task/ops/inflight.ts | lib/services/dashboard/, lib/model/entities/task/ | Phase 13 |
Remove the long tail of unused/dead small exports (ResolverKind, MILESTONE_VERSION_PATTERN, PRINCIPLE_CATEGORY_PATTERN, projectSeedSet, Section type, task claims/ default exports, CheckNamespaceConflictOptions, claudeHome, hydrateFrontmatter, cli/sdlc.ts’s and registry_adapter.ts’s dead re-exports) | lib/model/, lib/services/, cli/ | Phase 13 |
Wire or delete quality.baseline.prune — the one clear orphaned CLI op (baselines accumulate unbounded under .sdlc/) | lib/services/quality/, skills/project-cleanup/ | Phase 13 |
Move-out
Section titled “Move-out”| Task | Areas | Target phase |
|---|---|---|
Move the update-skill-doc skill out of the general skill set into repo-level tooling — it hardcodes solutions/ontological/skills/<slug>/SKILL.md, a dev-on-plugin concern no downstream consumer needs | skills/update-skill-doc/ | Phase 3 (the vault-conversion phase already rewires skill-file consumers in one PR) |
Move the plugin_source config key (and the gates that key it: skill-prose, corpus-invocation, docs-site) out of SdlcConfigSchema into repo-level tooling — only meaningful for a checkout hosting SDLC’s own source | lib/config/load.ts, lib/services/gate/ | Phase 5 (full sdlc.yaml, meta-defined — where config-key scope gets decided) |
Refactor
Section titled “Refactor”| Task | Areas | Target phase |
|---|---|---|
Consolidate the 3 duplicated lease-payload-mint call sites into buildInitialTaskLeasePayload; make ops/task/transition.ts delegate to transitionLease(); split loadReconcileState into a categorizeRefs helper | lib/services/lease/ | Phase 13 |
Split docs/generate.ts (852 lines, 8 concerns) per the site/reference.ts precedent; extract the duplicated titleOf+sort block into sortByTitle | lib/services/docs/ | Phase 13 |
Fix the util/config “single home” violations as one sweep: resolveProjectRoot → findAncestor; delete the misnamed local pyResolve (migrate-runtime-state, also flagged in skills-scripts); migrate the remaining raw yaml-package imports onto @lib/util/yaml; config/merge.ts’s isPlainObject → isRecord; nowIsoUtc → rfc3339(nowUtc()); verify/changes.ts’s inline ISO-date → todayUtc(); lease/tree.ts’s nowCommitDate → composed rfc3339; the 4 inline cmpStr-shaped comparators → cmpStr; the singularize/pluralize non-inverse split | lib/config/, lib/util/, lib/services/lease/, lib/services/verify/, lib/model/entities/task/, lib/services/project/, lib/services/gate/, skills/task-work/, skills/migrate-runtime-state/ | Phase 13 |
Factor the triplicated session() helper in host/hosts/{cmux,orca,terminal}.ts into one shared function | lib/services/host/ | Phase 13 |
Move the hand-rolled .gitignore glob compiler and Python-mtime formatter out of project/ops/scan-candidates.ts into lib/util/ | lib/services/project/, lib/util/ | Phase 13 |
Replace project/ops/setup.ts’s hand-rolled readLeaseAuthority with @lib/config’s resolveAuthority; extract a shared parseDashboardArgs for dashboard-service.ts/dashboard-service-main.ts | lib/services/project/, lib/services/dashboard/ | Phase 13 |
Extract a shared plugin/registry.ts (readPluginRegistry/loadJson) for info-report.ts’s and resolve.ts’s duplicated JSON-load and registry-parsing logic | lib/services/plugin/ | Phase 13 |
Dedupe the “pre-existing findings” computation between quality/ops/run.ts and baseline/diff.ts into baseline.ts; split run.ts’s 200-line handler; add the missing test for verify/ops/changes.ts and consider splitting its render/report concerns out | lib/services/quality/, lib/services/verify/ | Phase 13 |
Hoist the duplicated MigrationError class (capability + task entities) to one shared home; extract a shared reviewFindingSchemas(entityNoun) factory for the ~95%-duplicated principle/standard review-report schemas | lib/model/entities/, lib/services/report/ | Phase 13 |
Split the oversized functions flagged across shards: applyVerdict (task-ensure-ready, 240 lines), buildCapabilityCoverage/buildCapabilityGraph (capability ops), runMigrate/runValidateFrontmatter (model/ops) | skills/task-ensure-ready/, lib/model/entities/capability/, lib/model/ops/ | Phase 13 |
Consolidate small duplicated helpers: a shared pyJsonDumps for the two Python-JSON encoders (scan_corpus_assumptions.ts, dedup_search.ts); promote rjust/pad duplicates to lib/util/strings.ts (or use padEnd); dedupe the run() build helper in build-binary.ts/build-npm-wrapper.ts; add @sdlc:ignore-spawn markers and swap touch spawns for writeFileSync in scripts/compiled/bootstrap.ts | skills/, lib/util/, scripts/ | Phase 13 |
Replace the raw child_process.spawnSync command-seam violations in cli/tests/lease_dispatch.test.ts and cli/backlog_cli/tests/create.test.ts; dedupe the ad hoc Bun.spawn test capture helpers onto _cli_harness.ts | cli/tests/, cli/task_cli/, cli/backlog_cli/ | Phase 13 |
lib/util/git.ts’s worktree-detection helpers — derive from @sksizer/easy-git’s mainCheckoutFrom/worktrees() instead of an independent filesystem scan, or document the divergence | lib/util/ | Phase 13 |
Wire sdlc verify changes into the judge workflow step — the op exists and is documented as core to the phase gate, but nothing invokes it yet | lib/services/verify/, sdlc.yaml workflows | Phase 2 |
Wire pr survey/pr update into orchestrate’s merges loop (built, tested, described in the plan’s execution model, but currently unwired) — or drop them from the plan if the design changes | lib/services/pr/, lib/services/orchestrator/ | Phase 2 |
| Task | Areas | Target phase |
|---|---|---|
Fix the dead-doc-link and false claim comments that are user- or config-facing: python-runtime.md dead link (already fixed as of the current head — see the Lease + orchestrator finding above)_skill_prose_contract.ts’s “14 skills” header; verb-list.ts’s false _SDLC_YAML_HEADER claim; the stale T-MBOK note in config/sdlc_yaml.ts; the stale docs_site .describe() claim about list-ops.ts (leaks into every consumer’s scaffolded sdlc.yaml) | lib/services/gate/, lib/services/config/, lib/config/ | Phase 13 |
Fix the 7 stale plugin/-tree path comments (with wrong segment counts) in the docs test files | lib/services/docs/tests/ | Phase 13 |
Fix the stale migrate_entities.ts/validate_frontmatter.ts shim comments describing removed forwarding shims as still-pending | lib/model/ops/ | Phase 13 |
Fix the stale date-slug wikilink and hardcoded dead path in lint-state-origin.ts and its 2 sibling files | lib/model/entities/task/ | Phase 13 |
Fix the stale CLI docs cluster: task_cli/backlog_cli READMEs referencing deleted files and a test-placement mismatch; the backlog_cli exit-code doc (8 → 16; “lease owns 2-7” → 10-13) | cli/task_cli/, cli/backlog_cli/ | Phase 13 |
Sweep the remaining stale “mirrors the Python tier” / deleted-file comments: backlog_cli’s 5 “mirrors …py” comments, scan_corpus_assumptions.ts’s scan_placeholders.ts references, schema-bump-checklist.md’s audit_entities.ts/migrate_entities.ts, lease/tree.ts’s stale “CLI wrapper” header | cli/backlog_cli/, skills/task-ensure-ready/, conventions/, lib/services/lease/ | Phase 13 |
Close out the remaining PR1/PR2 stale-comment leftovers from the July audit: quality/ops/run.ts:44, the 3 task files still citing run-checks.ts, zod_introspect.ts’s missing orphan note, RF-0004’s Summary/Notes contradiction | lib/services/quality/, docs/planning/tasks/, docs/planning/decisions/ | Phase 13 |
Fix the two CLI help-generation bugs: sdlc dashboard --help’s empty op-list summary; pr classify’s --advanced-hidden status vs. pr survey/update’s primary visibility (inverted from actual usage) | cli/, lib/services/pr/ | Phase 13 |
29 tasks total: 4 Prune, 2 Move-out, 15 Refactor, 8 Fix.
Verification methodology
Section titled “Verification methodology”All 9 blocking findings across the 12 code-quality shards were independently re-checked against
the current tree (all 9 confirmed, 0 false positives). A ~65% sample of major findings (20 of a
recounted 31 total, spanning 11 of the 12 shards — the 12th, workspace-deps, has zero majors) was
independently re-checked the same way: 19 confirmed outright, and 1 confirmed with a caveat — the
entities-other principle/standard schema-duplication finding is real and correctly rated Major,
but its supporting claim that a third near-identical copy exists at task/reports/review/schema.ts
(“3x, not 2x”) is factually wrong; that file is a structurally unrelated whole-backlog report
schema. The finding’s severity is unaffected since the 2x duplication alone justifies it. Combined,
29 of 29 sampled blocking/major findings held up (100%), with the one sub-claim above
downgraded from “3x” to “2x.” Minor-severity findings (59 total) were not independently sampled.
Two minor QA notes surfaced during verification, neither disqualifying:
p4-quality-misc-services.md’s own summary line stated “Major: 5” while only 4 findings are
actually tagged major in its body (corrected in this document’s Misc services subsection), and a
similar one-off discrepancy was found and corrected for the docs-designtokens and gate-pr shards’
self-reported major counts against their own bodies. These are bookkeeping slips in the raw shard
files, not defects in the underlying code findings.