Takedown design phase must lint the design's tests and code before the design is final #1005

Closed
opened 2026-10-14 17:14:24 +00:00 by jared · 5 comments
Owner

Problem

A takedown design becomes final without lint. The design phase proves the failing tests red at base (red_check) and, since ADR-0291, that the target suites pass. It never runs rubocop on the design's Ruby files. The takedown-implement node place-tests gates on test-lint. ADR-0290 forbids model edits of placed content, so no node can repair a lint failure at that point. A design that is red for the intended reason can therefore fail at implement time. This blocks the D2 tracer and every #975 trial ticket.

The previous design for this ticket (run docs/takedown/1005-20261014-151342) only failed the run on offenses. It had no repair step. ADR-0293 supersedes it.

Observed

On 2026-10-14, implementation 43 (#1004, design docs/takedown/1004-20261014-124517/final-design.json) escalated at place-tests (dispatch 376, escalation 22). diff-test classified the run red, which is the expected result. test-lint failed with 10 offenses in plugins/os-sdlc/eval/ticket-takedown/test/command/final_suite_test.rb:

5    Sdlc/Structural/MutableCollectionLeakViaAttrReader
15   Metrics/PerceivedComplexity 5/4
17, 32, 64, 153  Layout/LineLength
31, 33  Sdlc/Dry/RepeatedLiteralArgument
74   Metrics/AbcSize 15.52/15
95   Sdlc/Structural/RawFileContentAssertion

The previous #1005 design (run 1005-20261014-151342) had 2 offenses. The old ProjectSuites#lint_target also had a defect: a target with path: "." linted no files, so such a design always looked clean.

Reproduce

n/a for the #1004 failure: it shows in the records of implementation 43, dispatch 376, escalation 22. For the path: "." defect: give a design Ruby files with offenses and a target whose path is "."; the lint step reports no files.

Approach

Required work: none beyond the acceptance criteria. Behavior is fixed by ADR-0293 (Accepted 2026-10-15, Jared's ruling; amends ADR-0291). The design is open. OsSdlc::Project::Target already owns the target and lint_config rules; the design may reuse it (open question in docs/research/lint-lessons/metrics-perceived-complexity.md).

Pinning tests that change (all under plugins/os-sdlc/eval/ticket-takedown/): test/command/final_suite_test.rb, test/controller/run_cli_test.rb (line 12 and line 114), test/command/pipeline_test.rb (line 442, the key set), test/model/harness_files_test.rb (line 16, the card set; line 156, the schema set: run 1005-20261015-101625 adds polisher.md and polish.json).

Implementation route: use the poodr-ticket-implementation map, not takedown-implement. The pipeline cannot polish its own fix (bootstrap, ADR-0293 consequences). The next ticket after this one becomes the D2 tracer.

Slice

This ticket is slice 1 of 2 (split 2026-10-15 after blast radius: about 12 lib files and 5 test files in one run is too large). Slice 1 builds AC 1, 3, 4, 9 and 10, with one change: in this slice a lint-red green-suite (AC 2) fails the run and names each offense; it does not go to polish. Slice 2 (polish, guard, limits, polish_rounds: AC 2, 5, 6, 7, 8) is #1009, which is blocked by this one. AC 2, 5, 6, 7 and 8 below stay as the target behavior; they are out of scope for this slice.

Decision (agent, AFK, 2026-10-15): a test-red green-suite after the critique limit is reached (no reviser profile is left; revision_rule.rb:14, step_profile.rb) fails the run, and the design is not final. No reviser rounds are added beyond the limit.

Pinning tests for this slice: test/command/final_suite_test.rb (rename), test/controller/run_cli_test.rb (line 12, line 114). Also check test/command/pipeline_test.rb:258, test/run_support.rb and test/report_support.rb. ProjectSuites::Target has no path or lint_config; reuse OsSdlc::Project::Target (lib/os_sdlc/model/project/target.rb:19, lint_path already handles ".").

Acceptance criteria

  1. Given a live run whose design test suites pass and whose Ruby files have no new offenses, when green-suite runs, then the run records the design as final. The step was called final-suite before; old run records keep that name.
  2. Given a live run with passing suites and at least one offense under the target's lint_config that is not present at base, when green-suite runs, then the next step is polish, and green-suite runs again after it. Offenses that exist at base are not counted.
  3. Given a target whose path is ".", when green-suite lints, then it lints the design's Ruby files at the repo root.
  4. Given a live run with failing suites, when green-suite runs, then the run returns to revise; the new idea is graded again; the return counts toward the existing critique round limit (3).
  5. Given polish runs, then its input is the offenses and the lint lesson from plugins/os-sdlc/lint-lessons/ (read through Lesson::Relay) when one exists for the cop. It never receives the ruling or the grade. It changes form only.
  6. Given polish returns files, when the guard runs, then the target suites pass and the design's failing tests are still red at base. If either check fails, the polish round does not count as a success.
  7. Given polish has run 5 rounds, or a round does not lower the offense count, when the limit is reached, then the run escalates and the design is not final.
  8. Given a polished final design, then the grade stays on the unpolished design (its own step record), final-design.json holds the polished files, source_step names the graded design, and a new polish_rounds field holds the polish count. place-design, the implement body and the takedown-implement map keep reading final-design.json.
  9. Given eval case mode, then green-suite and polish do not run, and eval grades stay comparable with earlier runs.
  10. Given the #1004 design files, when green-suite runs on them, then it names each offense with its cop, path and line.

Owner sketch

class Takedown::GreenSuiteStep      # replaces FinalSuiteStep; name "green-suite"
  def call(run)                     # suites + lint; outcome :record, :revise, or failed with offenses
end

class Takedown::SuiteCheck
  def self.run(...)                 # gains the lint pass: offenses new against base only
end

class Takedown::ProjectSuites::Target  # path + lint_config, through OsSdlc::Project::Target#lint_path
end

Origin

  • Trigger: /os-sdlc:implement 1004 takedown-implement (implementation 43), escalation 22 at place-tests
  • Re-scoped 2026-10-15 per ADR-0293 (Jared's ruling). Old design run 1005-20261014-151342 is superseded.
  • Improvised this session: none
  • Chain: place-tests fails test-lint ← the design was never linted ← the design phase checks only red at base and green suites ← DESIGN: ADR-0283 decision 3, ADR-0290 (no model edits of placed content), ADR-0291 (final-suite without lint)
  • Root candidate: this ticket
  • Related: ADR-0293, ADR-0291, ADR-0290, #1004, docs/handoffs/2026-10-15-lint-lesson-analysis.md
  • Where: plugins/os-sdlc/eval/ticket-takedown/lib/takedown/command/flow.rb; plugins/os-sdlc/eval/ticket-takedown/lib/takedown/command/final_suite_step.rb; plugins/os-sdlc/eval/ticket-takedown/lib/takedown/model/suite_check.rb; plugins/os-sdlc/eval/ticket-takedown/lib/takedown/model/run_state.rb
  • Session: d3ae2369-7f15-41bc-be58-4a91e74042c9
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-prism-architect/d3ae2369-7f15-41bc-be58-4a91e74042c9.jsonl

VERDICT: CREATE — observed failure from an in-policy run (implementation 43, escalation 22); it blocks D2 and D3; chain ends in DESIGN.

## Problem A takedown design becomes final without lint. The design phase proves the failing tests red at base (`red_check`) and, since ADR-0291, that the target suites pass. It never runs rubocop on the design's Ruby files. The `takedown-implement` node `place-tests` gates on `test-lint`. ADR-0290 forbids model edits of placed content, so no node can repair a lint failure at that point. A design that is red for the intended reason can therefore fail at implement time. This blocks the D2 tracer and every #975 trial ticket. The previous design for this ticket (run `docs/takedown/1005-20261014-151342`) only failed the run on offenses. It had no repair step. ADR-0293 supersedes it. ## Observed On 2026-10-14, implementation 43 (#1004, design `docs/takedown/1004-20261014-124517/final-design.json`) escalated at `place-tests` (dispatch 376, escalation 22). `diff-test` classified the run `red`, which is the expected result. `test-lint` failed with 10 offenses in `plugins/os-sdlc/eval/ticket-takedown/test/command/final_suite_test.rb`: ``` 5 Sdlc/Structural/MutableCollectionLeakViaAttrReader 15 Metrics/PerceivedComplexity 5/4 17, 32, 64, 153 Layout/LineLength 31, 33 Sdlc/Dry/RepeatedLiteralArgument 74 Metrics/AbcSize 15.52/15 95 Sdlc/Structural/RawFileContentAssertion ``` The previous #1005 design (run 1005-20261014-151342) had 2 offenses. The old `ProjectSuites#lint_target` also had a defect: a target with `path: "."` linted no files, so such a design always looked clean. ## Reproduce n/a for the #1004 failure: it shows in the records of implementation 43, dispatch 376, escalation 22. For the `path: "."` defect: give a design Ruby files with offenses and a target whose `path` is "."; the lint step reports no files. ## Approach Required work: none beyond the acceptance criteria. Behavior is fixed by ADR-0293 (Accepted 2026-10-15, Jared's ruling; amends ADR-0291). The design is open. `OsSdlc::Project::Target` already owns the target and `lint_config` rules; the design may reuse it (open question in `docs/research/lint-lessons/metrics-perceived-complexity.md`). Pinning tests that change (all under `plugins/os-sdlc/eval/ticket-takedown/`): `test/command/final_suite_test.rb`, `test/controller/run_cli_test.rb` (line 12 and line 114), `test/command/pipeline_test.rb` (line 442, the key set), `test/model/harness_files_test.rb` (line 16, the card set; line 156, the schema set: run `1005-20261015-101625` adds `polisher.md` and `polish.json`). Implementation route: use the `poodr-ticket-implementation` map, not `takedown-implement`. The pipeline cannot polish its own fix (bootstrap, ADR-0293 consequences). The next ticket after this one becomes the D2 tracer. ## Slice This ticket is slice 1 of 2 (split 2026-10-15 after blast radius: about 12 lib files and 5 test files in one run is too large). Slice 1 builds AC 1, 3, 4, 9 and 10, with one change: in this slice a lint-red `green-suite` (AC 2) fails the run and names each offense; it does not go to `polish`. Slice 2 (`polish`, guard, limits, `polish_rounds`: AC 2, 5, 6, 7, 8) is #1009, which is blocked by this one. AC 2, 5, 6, 7 and 8 below stay as the target behavior; they are out of scope for this slice. Decision (agent, AFK, 2026-10-15): a test-red `green-suite` after the critique limit is reached (no reviser profile is left; `revision_rule.rb:14`, `step_profile.rb`) fails the run, and the design is not final. No reviser rounds are added beyond the limit. Pinning tests for this slice: `test/command/final_suite_test.rb` (rename), `test/controller/run_cli_test.rb` (line 12, line 114). Also check `test/command/pipeline_test.rb:258`, `test/run_support.rb` and `test/report_support.rb`. `ProjectSuites::Target` has no `path` or `lint_config`; reuse `OsSdlc::Project::Target` (`lib/os_sdlc/model/project/target.rb:19`, `lint_path` already handles "."). ## Acceptance criteria 1. Given a live run whose design test suites pass and whose Ruby files have no new offenses, when `green-suite` runs, then the run records the design as final. The step was called `final-suite` before; old run records keep that name. 2. Given a live run with passing suites and at least one offense under the target's `lint_config` that is not present at base, when `green-suite` runs, then the next step is `polish`, and `green-suite` runs again after it. Offenses that exist at base are not counted. 3. Given a target whose `path` is ".", when `green-suite` lints, then it lints the design's Ruby files at the repo root. 4. Given a live run with failing suites, when `green-suite` runs, then the run returns to `revise`; the new idea is graded again; the return counts toward the existing critique round limit (3). 5. Given `polish` runs, then its input is the offenses and the lint lesson from `plugins/os-sdlc/lint-lessons/` (read through `Lesson::Relay`) when one exists for the cop. It never receives the ruling or the grade. It changes form only. 6. Given `polish` returns files, when the guard runs, then the target suites pass and the design's failing tests are still red at base. If either check fails, the polish round does not count as a success. 7. Given polish has run 5 rounds, or a round does not lower the offense count, when the limit is reached, then the run escalates and the design is not final. 8. Given a polished final design, then the grade stays on the unpolished design (its own step record), `final-design.json` holds the polished files, `source_step` names the graded design, and a new `polish_rounds` field holds the polish count. `place-design`, the implement body and the `takedown-implement` map keep reading `final-design.json`. 9. Given eval case mode, then `green-suite` and `polish` do not run, and eval grades stay comparable with earlier runs. 10. Given the #1004 design files, when `green-suite` runs on them, then it names each offense with its cop, path and line. ## Owner sketch ```ruby class Takedown::GreenSuiteStep # replaces FinalSuiteStep; name "green-suite" def call(run) # suites + lint; outcome :record, :revise, or failed with offenses end class Takedown::SuiteCheck def self.run(...) # gains the lint pass: offenses new against base only end class Takedown::ProjectSuites::Target # path + lint_config, through OsSdlc::Project::Target#lint_path end ``` ## Origin - Trigger: `/os-sdlc:implement 1004 takedown-implement` (implementation 43), escalation 22 at `place-tests` - Re-scoped 2026-10-15 per ADR-0293 (Jared's ruling). Old design run 1005-20261014-151342 is superseded. - Improvised this session: none - Chain: `place-tests` fails `test-lint` ← the design was never linted ← the design phase checks only red at base and green suites ← `DESIGN`: ADR-0283 decision 3, ADR-0290 (no model edits of placed content), ADR-0291 (final-suite without lint) - Root candidate: this ticket - Related: ADR-0293, ADR-0291, ADR-0290, #1004, `docs/handoffs/2026-10-15-lint-lesson-analysis.md` - Where: plugins/os-sdlc/eval/ticket-takedown/lib/takedown/command/flow.rb; plugins/os-sdlc/eval/ticket-takedown/lib/takedown/command/final_suite_step.rb; plugins/os-sdlc/eval/ticket-takedown/lib/takedown/model/suite_check.rb; plugins/os-sdlc/eval/ticket-takedown/lib/takedown/model/run_state.rb - Session: d3ae2369-7f15-41bc-be58-4a91e74042c9 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-prism-architect/d3ae2369-7f15-41bc-be58-4a91e74042c9.jsonl VERDICT: CREATE — observed failure from an in-policy run (implementation 43, escalation 22); it blocks D2 and D3; chain ends in DESIGN.
Author
Owner

Blocked by #1006 (relevance step returns needs_ruling when an Accepted amending ADR resolves the conflict). Jared ruled 2026-10-14: take #1006 first, then run the #1005 tracer. The Forgejo CLI has no dependency link, so this comment records the edge.

Blocked by #1006 (relevance step returns needs_ruling when an Accepted amending ADR resolves the conflict). Jared ruled 2026-10-14: take #1006 first, then run the #1005 tracer. The Forgejo CLI has no dependency link, so this comment records the edge.
Author
Owner

Re-scoped 2026-10-15 per ADR-0293 (Jared's ruling). Old body saved in session; previous design run 1005-20261014-151342 is superseded.

Re-scoped 2026-10-15 per ADR-0293 (Jared's ruling). Old body saved in session; previous design run 1005-20261014-151342 is superseded.
Author
Owner

Work started 2026-10-15 (session fb136c57) on branch prism-architect. Route: /os-sdlc:implement 1005 poodr-ticket-implementation (Jared ruling, predicted then accepted). Blast-radius check first. Run 1005-20261015-101625 (failed at final-suite) is a non-final reference only. Polish limit is 5 rounds (Jared ruling 2026-10-15).

Work started 2026-10-15 (session fb136c57) on branch prism-architect. Route: /os-sdlc:implement 1005 poodr-ticket-implementation (Jared ruling, predicted then accepted). Blast-radius check first. Run 1005-20261015-101625 (failed at final-suite) is a non-final reference only. Polish limit is 5 rounds (Jared ruling 2026-10-15).
Author
Owner

Skeptic DROP (A15 layout follow-up): depth-1 rule; same defect class as #946. Note posted on #946 to consider widening scope to the takedown eval lib after #1009.

Skeptic DROP (A15 layout follow-up): depth-1 rule; same defect class as #946. Note posted on #946 to consider widening scope to the takedown eval lib after #1009.
Author
Owner

Resolution

Done: Slice 1 of ADR-0293 built via poodr-ticket-implementation (implementation 45, 8 dispatches, 10 min): final-suite renamed green-suite; SuiteCheck runs rubocop with the target lint_config, counting only offenses new against base; target path '.' lints the repo root; lint-red fails the run naming cop, path and line; test-red returns to revise within critique limit 3, then fails the run; eval case mode skips green-suite. Pinning tests final_suite_test.rb and run_cli_test.rb updated.

Evidence: Commit 984d9f3c on prism-architect (runner commit, suite-check gate green, behavior-verifier pass, contract-auditor pass). Records 389171a4 (README step table, os-sdlc leaf History row). Lens signals a9853e9b (P2), 9e135aef (A15) on main.

Follow-ups: #1009 (slice 2: polish, guard, 5-round limit, polish_rounds; now also LintRun injection from the P2 lens challenge). A15 layout follow-up: skeptic DROP, noted on #946.

## Resolution **Done:** Slice 1 of ADR-0293 built via poodr-ticket-implementation (implementation 45, 8 dispatches, 10 min): final-suite renamed green-suite; SuiteCheck runs rubocop with the target lint_config, counting only offenses new against base; target path '.' lints the repo root; lint-red fails the run naming cop, path and line; test-red returns to revise within critique limit 3, then fails the run; eval case mode skips green-suite. Pinning tests final_suite_test.rb and run_cli_test.rb updated. **Evidence:** Commit 984d9f3c on prism-architect (runner commit, suite-check gate green, behavior-verifier pass, contract-auditor pass). Records 389171a4 (README step table, os-sdlc leaf History row). Lens signals a9853e9b (P2), 9e135aef (A15) on main. **Follow-ups:** #1009 (slice 2: polish, guard, 5-round limit, polish_rounds; now also LintRun injection from the P2 lens challenge). A15 layout follow-up: skeptic DROP, noted on #946.
jared closed this issue 2026-10-15 16:18:34 +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#1005
No description provided.