CRC census prepares its own ledger; remove ledger work from fast-batch #1398

Closed
opened 2026-10-26 15:08:34 +00:00 by jared · 3 comments
Owner

Problem

New source files between CRC runs are normal. Today they are treated as a defect:

  • plugins/os-sdlc/bin/crc-ledger-check --target os-sdlc docs/crc/os-sdlc exits 1 on main at 356eb506 with 96 "no ledger row" problems (92 when this ticket was first filed).
  • The fast-batch close checklist requires that check to exit 0 (plugins/os-sdlc/skills/fast-batch/references/close-checklist.md:8, references/batch-brief.md:67 "It must exit 0. Add a ledger row for each new Ruby file.", skills/fast-batch/SKILL.md:50, docs/sdlc-fast-path.md:14 and :34). So every fast batch must manage CRC ledger rows or accept a red check (fast-batch-16 ruling A-R1).
  • The layer cops read the ledger role column. UnlayeredConstant (lib/os_sdlc/cops/structural/unlayered_constant.rb:14) reports an offense for a constant with no row, and also for a row whose role cell is empty (layer_ledger/layer_map.rb:43-46). So new code fails lint until a CRC run classifies it.

Jared's ruling (session 006abca1, 2026-10-26): no AI outside a CRC run manages ledger rows. The CRC run brings its own ledger up to date when it starts or resumes, with code that already exists (crc-census). There is no separate check step for an agent to call. Readiness is data in the report, not an exit code.

Approach

Decision 1 = P: keep the crc-refactor flow as skill prose; make start and resume one idempotent code call. Decision 2 = A: the layer cops treat a file that is not yet classified (no ledger row, or a row with an empty role cell) as "no offense" until the next CRC run gives it a role. A row with a non-empty role that maps to no layer still reports, as today.

Required work:

  1. crc-census JSON report gains three keys and keeps every existing key (ok, appended, problems, totals, vocabulary_words, batches, and scope through ScopedReport): ready (bool), missing ({"job": [<ledger paths whose job cell is empty>]}), and ledger_problems (the applied-row and gone-row problems that OsSdlc::Crc::Ledger::Check finds; census reuses Check, no logic is copied). ready is true only when missing.job and ledger_problems are empty. The exit code is unchanged: it still follows ok, never ready. — check: present ledger_problems in plugins/os-sdlc/lib/os_sdlc/crc/census/report.rb
  2. Delete the crc-ledger-check CLI: plugins/os-sdlc/bin/crc-ledger-check, lib/os_sdlc/crc/ledger/check/run.rb, its Boot registration (lib/os_sdlc/boot/commands.rb:92-94, boot/inputs.rb:135, boot/inputs/usage_text.rb:111), and tests/crc/ledger_check_bin_test.rb. Move each applied-row, moved-row and gone-row behavior that test pins into a census test. Drop its unlisted-row and usage-exit cases. Ledger::Check stays as a library object. — check: absent crc-ledger-check in plugins/os-sdlc/lib/os_sdlc/boot/commands.rb
  3. Crc::WaveProgress owns wave-progress.json. record keeps keys it does not write, so a stored since survives. When census runs with --since <sha>, it stores the SHA as since through WaveProgress. When census runs without --since and the file holds a since, census settings use it. — check: present since in plugins/os-sdlc/lib/os_sdlc/crc/wave_progress.rb
  4. skills/crc-refactor/SKILL.md: Phase 0 (resume) and Phase 1 (new run) both start with one census call and follow its report: dispatch crc-job-writer for the missing.job files, merge with crc-jobs, run census again until ready is true; stop and report if it is still false after one job-writer round. Remove the crc-ledger-check row (SKILL.md:32) and update references/ledger.md:43. — check: present "ready": true in plugins/os-sdlc/skills/crc-refactor/SKILL.md
  5. Remove all ledger work from fast-batch: the ledger row in references/close-checklist.md:8, the sentence at references/batch-brief.md:67, the mention at skills/fast-batch/SKILL.md:50, and the ledger items in docs/sdlc-fast-path.md:14 and :34. Leave history rows and dated records unchanged. — check: absent crc-ledger-check in plugins/os-sdlc/skills/fast-batch/**/*.md
  6. UnlayeredConstant: a constant with no ledger row, or with a row whose role cell is empty, produces no offense. InwardDependency already yields no edge when either layer is nil (layer_map.rb:57) and EffectInModel already returns early when the role is nil (effect_in_model.rb:25); keep both as they are. The detector count that reads UnlayeredConstant (lib/os_sdlc/detector/inward_edges.rb:7) drops with it; that is intended.

Acceptance criteria

  1. Given a ledger that lacks rows for two files on disk, when crc-census --target <project> <docs dir> runs, then it appends two rows and prints JSON with "ready": false, both paths under missing.job, and the existing ok and appended keys.
  2. Given the same ledger after a second census run with no file changes, then no rows are added and appended is empty.
  3. Given a ledger where every row has a job sentence and no applied-row or gone-row problem exists, when census runs, then it prints "ready": true and exits 0.
  4. Given a deleted source file that still has a row, when census runs, then the gone-row problem appears in ledger_problems and ready is false.
  5. Given crc-census --since <sha> ran once, when census runs again without --since, then it uses the stored SHA from wave-progress.json, and the file still holds wave, tickets_done and tickets_total after WaveProgress#record.
  6. Given main after this ticket, plugins/os-sdlc/bin/crc-ledger-check does not exist and no live instruction in plugins/os-sdlc/skills or docs/sdlc-fast-path.md names it (history rows excepted).
  7. Given a Ruby file whose constant has no ledger row, or a row with an empty role cell, when the sweep config runs UnlayeredConstant and InwardDependency on it, then neither reports an offense.
  8. Given a row whose role is non-empty and maps to no layer, when UnlayeredConstant runs, then it still reports the offense.

Owner sketch

# census owns ledger preparation and readiness; Ledger::Check stays the problem finder
report = OsSdlc::Crc::Census.new(settings).call   # appends unlisted rows (exists today)
report.to_h
# => { ok: true, appended: [...], problems: [...], totals: {...}, ...,
#      ready: false, missing: { job: [...] }, ledger_problems: [...] }
#   missing         <- ledger rows with an empty job cell
#   ledger_problems <- Ledger::Check applied-row and gone-row problems
#   ready           <- missing[:job].empty? && ledger_problems.empty?

# WaveProgress owns wave-progress.json, including the resume SHA
WaveProgress.new(root).since          # => "c1634d62" or nil
settings.since # => --since flag, else WaveProgress#since, else nil

# UnlayeredConstant: not yet classified means no offense
role = ledger.role_by_const(const)
return if role.nil? || role.empty?

Origin

  • Trigger: fast-batch-16 close checklist (#1397), ledger item red before and after the batch.
  • Rewritten 2026-10-26 in session 006abca1 after Jared ruled that new files between CRC runs are normal and the CRC run owns its ledger. Second opinion (Opus) chose P over a flow object or a full Runner: the ledger cells already hold resume state; past failures came from ad hoc scripts, not from the AI's step order.
  • Revised after change-auditor dispatch 1509 (implementation 174): R4 and R6 mapped to checks and criteria; empty-role rows, report keys, exit code, and the since owner made explicit.
  • Where: plugins/os-sdlc/lib/os_sdlc/crc/, plugins/os-sdlc/skills/crc-refactor/, plugins/os-sdlc/skills/fast-batch/, plugins/os-sdlc/lib/os_sdlc/cops/structural/
  • Session: 006abca1-0754-41ab-a8f7-9209dfff5f62
## Problem New source files between CRC runs are normal. Today they are treated as a defect: - `plugins/os-sdlc/bin/crc-ledger-check --target os-sdlc docs/crc/os-sdlc` exits 1 on main at 356eb506 with 96 "no ledger row" problems (92 when this ticket was first filed). - The fast-batch close checklist requires that check to exit 0 (`plugins/os-sdlc/skills/fast-batch/references/close-checklist.md:8`, `references/batch-brief.md:67` "It must exit 0. Add a ledger row for each new Ruby file.", `skills/fast-batch/SKILL.md:50`, `docs/sdlc-fast-path.md:14` and `:34`). So every fast batch must manage CRC ledger rows or accept a red check (fast-batch-16 ruling A-R1). - The layer cops read the ledger `role` column. `UnlayeredConstant` (`lib/os_sdlc/cops/structural/unlayered_constant.rb:14`) reports an offense for a constant with no row, and also for a row whose role cell is empty (`layer_ledger/layer_map.rb:43-46`). So new code fails lint until a CRC run classifies it. Jared's ruling (session 006abca1, 2026-10-26): no AI outside a CRC run manages ledger rows. The CRC run brings its own ledger up to date when it starts or resumes, with code that already exists (`crc-census`). There is no separate check step for an agent to call. Readiness is data in the report, not an exit code. ## Approach Decision 1 = P: keep the crc-refactor flow as skill prose; make start and resume one idempotent code call. Decision 2 = A: the layer cops treat a file that is not yet classified (no ledger row, or a row with an empty role cell) as "no offense" until the next CRC run gives it a role. A row with a non-empty role that maps to no layer still reports, as today. Required work: 1. `crc-census` JSON report gains three keys and keeps every existing key (`ok`, `appended`, `problems`, `totals`, `vocabulary_words`, `batches`, and `scope` through `ScopedReport`): `ready` (bool), `missing` (`{"job": [<ledger paths whose job cell is empty>]}`), and `ledger_problems` (the applied-row and gone-row problems that `OsSdlc::Crc::Ledger::Check` finds; census reuses `Check`, no logic is copied). `ready` is true only when `missing.job` and `ledger_problems` are empty. The exit code is unchanged: it still follows `ok`, never `ready`. — check: present `ledger_problems` in `plugins/os-sdlc/lib/os_sdlc/crc/census/report.rb` 2. Delete the `crc-ledger-check` CLI: `plugins/os-sdlc/bin/crc-ledger-check`, `lib/os_sdlc/crc/ledger/check/run.rb`, its Boot registration (`lib/os_sdlc/boot/commands.rb:92-94`, `boot/inputs.rb:135`, `boot/inputs/usage_text.rb:111`), and `tests/crc/ledger_check_bin_test.rb`. Move each applied-row, moved-row and gone-row behavior that test pins into a census test. Drop its unlisted-row and usage-exit cases. `Ledger::Check` stays as a library object. — check: absent `crc-ledger-check` in `plugins/os-sdlc/lib/os_sdlc/boot/commands.rb` 3. `Crc::WaveProgress` owns `wave-progress.json`. `record` keeps keys it does not write, so a stored `since` survives. When census runs with `--since <sha>`, it stores the SHA as `since` through `WaveProgress`. When census runs without `--since` and the file holds a `since`, census settings use it. — check: present `since` in `plugins/os-sdlc/lib/os_sdlc/crc/wave_progress.rb` 4. `skills/crc-refactor/SKILL.md`: Phase 0 (resume) and Phase 1 (new run) both start with one census call and follow its report: dispatch `crc-job-writer` for the `missing.job` files, merge with `crc-jobs`, run census again until `ready` is true; stop and report if it is still false after one job-writer round. Remove the `crc-ledger-check` row (`SKILL.md:32`) and update `references/ledger.md:43`. — check: present `"ready": true` in `plugins/os-sdlc/skills/crc-refactor/SKILL.md` 5. Remove all ledger work from fast-batch: the ledger row in `references/close-checklist.md:8`, the sentence at `references/batch-brief.md:67`, the mention at `skills/fast-batch/SKILL.md:50`, and the ledger items in `docs/sdlc-fast-path.md:14` and `:34`. Leave history rows and dated records unchanged. — check: absent `crc-ledger-check` in `plugins/os-sdlc/skills/fast-batch/**/*.md` 6. `UnlayeredConstant`: a constant with no ledger row, or with a row whose role cell is empty, produces no offense. `InwardDependency` already yields no edge when either layer is nil (`layer_map.rb:57`) and `EffectInModel` already returns early when the role is nil (`effect_in_model.rb:25`); keep both as they are. The detector count that reads `UnlayeredConstant` (`lib/os_sdlc/detector/inward_edges.rb:7`) drops with it; that is intended. ## Acceptance criteria 1. Given a ledger that lacks rows for two files on disk, when `crc-census --target <project> <docs dir>` runs, then it appends two rows and prints JSON with `"ready": false`, both paths under `missing.job`, and the existing `ok` and `appended` keys. 2. Given the same ledger after a second census run with no file changes, then no rows are added and `appended` is empty. 3. Given a ledger where every row has a job sentence and no applied-row or gone-row problem exists, when census runs, then it prints `"ready": true` and exits 0. 4. Given a deleted source file that still has a row, when census runs, then the gone-row problem appears in `ledger_problems` and `ready` is false. 5. Given `crc-census --since <sha>` ran once, when census runs again without `--since`, then it uses the stored SHA from `wave-progress.json`, and the file still holds `wave`, `tickets_done` and `tickets_total` after `WaveProgress#record`. 6. Given main after this ticket, `plugins/os-sdlc/bin/crc-ledger-check` does not exist and no live instruction in `plugins/os-sdlc/skills` or `docs/sdlc-fast-path.md` names it (history rows excepted). 7. Given a Ruby file whose constant has no ledger row, or a row with an empty role cell, when the sweep config runs `UnlayeredConstant` and `InwardDependency` on it, then neither reports an offense. 8. Given a row whose role is non-empty and maps to no layer, when `UnlayeredConstant` runs, then it still reports the offense. ## Owner sketch ```ruby # census owns ledger preparation and readiness; Ledger::Check stays the problem finder report = OsSdlc::Crc::Census.new(settings).call # appends unlisted rows (exists today) report.to_h # => { ok: true, appended: [...], problems: [...], totals: {...}, ..., # ready: false, missing: { job: [...] }, ledger_problems: [...] } # missing <- ledger rows with an empty job cell # ledger_problems <- Ledger::Check applied-row and gone-row problems # ready <- missing[:job].empty? && ledger_problems.empty? # WaveProgress owns wave-progress.json, including the resume SHA WaveProgress.new(root).since # => "c1634d62" or nil settings.since # => --since flag, else WaveProgress#since, else nil # UnlayeredConstant: not yet classified means no offense role = ledger.role_by_const(const) return if role.nil? || role.empty? ``` ## Origin - Trigger: fast-batch-16 close checklist (#1397), ledger item red before and after the batch. - Rewritten 2026-10-26 in session 006abca1 after Jared ruled that new files between CRC runs are normal and the CRC run owns its ledger. Second opinion (Opus) chose P over a flow object or a full Runner: the ledger cells already hold resume state; past failures came from ad hoc scripts, not from the AI's step order. - Revised after change-auditor dispatch 1509 (implementation 174): R4 and R6 mapped to checks and criteria; empty-role rows, report keys, exit code, and the `since` owner made explicit. - Where: plugins/os-sdlc/lib/os_sdlc/crc/, plugins/os-sdlc/skills/crc-refactor/, plugins/os-sdlc/skills/fast-batch/, plugins/os-sdlc/lib/os_sdlc/cops/structural/ - Session: 006abca1-0754-41ab-a8f7-9209dfff5f62
jared changed title from Add CRC ledger rows for the 92 os-sdlc files that crc-ledger-check reports to CRC census prepares its own ledger; remove ledger work from fast-batch 2026-10-26 19:54:19 +00:00
Author
Owner

Rewritten 2026-10-26 (session 006abca1) to Decision 1 = P, Decision 2 = A per Jared's ruling. Work starts now through /os-sdlc:implement.

Rewritten 2026-10-26 (session 006abca1) to Decision 1 = P, Decision 2 = A per Jared's ruling. Work starts now through /os-sdlc:implement.
Author
Owner

Work started on branch ticket-1398 via /os-sdlc:implement.

Work started on branch ticket-1398 via /os-sdlc:implement.
Author
Owner

Resolution

Done: crc-census prepares its own ledger: JSON adds ready, missing.job, ledger_problems; WaveProgress stores the --since SHA; crc-ledger-check CLI, Check::Run and its test deleted; fast-batch and sdlc-fast-path no longer manage ledger rows; crc-refactor Phase 0/1 start with one census call; UnlayeredConstant skips constants with no row or empty role.

Evidence: main 39060aba (commit 0e225eb6). Suite 2687 runs 0 failures; 15 changed Ruby files lint clean; tests census_ready_bin_test.rb, census_stored_since_bin_test.rb, unlayered_constant_test.rb, inward_edges_test.rb; design audit findings 1-6 fixed (dead Check#call removed). Implementation 174 hand-finished after unexpected_pass escalation, then abandoned.

Follow-ups: none: the exit-code cop is #1402 (filed this session); the suite wall-time WARN (88s vs 60s budget) is pre-existing and not caused by this change; the 96 unlisted files get rows at the next CRC run by design.

## Resolution **Done:** crc-census prepares its own ledger: JSON adds ready, missing.job, ledger_problems; WaveProgress stores the --since SHA; crc-ledger-check CLI, Check::Run and its test deleted; fast-batch and sdlc-fast-path no longer manage ledger rows; crc-refactor Phase 0/1 start with one census call; UnlayeredConstant skips constants with no row or empty role. **Evidence:** main 39060aba (commit 0e225eb6). Suite 2687 runs 0 failures; 15 changed Ruby files lint clean; tests census_ready_bin_test.rb, census_stored_since_bin_test.rb, unlayered_constant_test.rb, inward_edges_test.rb; design audit findings 1-6 fixed (dead Check#call removed). Implementation 174 hand-finished after unexpected_pass escalation, then abandoned. **Follow-ups:** none: the exit-code cop is #1402 (filed this session); the suite wall-time WARN (88s vs 60s budget) is pre-existing and not caused by this change; the 96 unlisted files get rows at the next CRC run by design.
jared closed this issue 2026-10-26 20:42:50 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1398
No description provided.