Complete ClassFacts: entry?, routes_to, holds_state?, calls, and write facts to the output #1412

Closed
opened 2026-10-26 21:32:55 +00:00 by jared · 2 comments
Owner

Problem

#1403 shipped ClassFacts with one field, io, and pure?. The #1403 Approach listed six fields: io, pure?, entry?, routes_to, holds_state?, calls. Its acceptance criteria tested only io, so the pipeline built only io. #1404 writes the pattern catalog as Role predicates over these facts. The Layers, Command, and Ports-and-adapters predicates need entry?, routes_to, holds_state?, and calls.

Reproduce

cat plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb

Output: ClassFacts = Data.define(:io), with pure? and merge only.

Approach

Add the four missing fields to ClassFacts, fill each one in the extractor, and write the facts as data in the generated output. Definitions are in docs/system-design-format/pattern-matching.md section 2:

  • entry?: the class is called from bin/*, a hook, or a task. A Thor CLI class that a bin/ script starts is an entry.
  • routes_to: the classes this class selects between by request name (a CLI command dispatching to one command class per command).
  • holds_state?: the class assigns an instance variable outside initialize.
  • calls: the classes this class sends messages to. A call to another class is a calls edge, not I/O.

The extractor today is Extractor plus Extractor::IoLedger and the Prism visitor Extractor::IoScan. IoLedger#facts builds ClassFacts.new(io: entries). The writers (Writer, Writer::DirectoryFile, Writer::JourneyFile) emit .c4 text only and do not write facts.

One item per field; each check names a distinct symbol.

Required work:

  1. Add entry? to ClassFacts and fill it from bin/*, hook, and task callers — check: present entry in plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb
  2. Add routes_to and fill it from request-name dispatch — check: present routes_to in plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb
  3. Add holds_state? and fill it from instance-variable assignment outside initialize — check: present holds_state in plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb
  4. Add calls and fill it from constant-receiver message sends — check: present calls in plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb
  5. Write Model#facts as one data file in the generated output — check: present facts in plugins/os-sdlc/lib/os_sdlc/system_model/writer.rb

Acceptance criteria

One criterion per Approach item, each with a positive and a negative case where the field has one.

  1. Given plugins/os, when facts are generated, then the facts for Worktree::CLI show entry? true.
  2. Given plugins/os, when facts are generated, then the facts for Handoff::Document show entry? false.
  3. Given plugins/os, when facts are generated, then the facts for Worktree::CLI list Worktree::FinishCommand in routes_to.
  4. Given plugins/os, when facts are generated, then the facts for Handoff::Document show an empty routes_to.
  5. Given plugins/os, when facts are generated, then the facts for Worktree::FinishCommand (assigns @pre_merge_head in merge_into_base) show holds_state? true.
  6. Given a class with no instance variables set outside initialize, when facts are generated, then holds_state? is false.
  7. Given plugins/os, when facts are generated, then the facts for Handoff::CLI list Handoff::Store in calls.
  8. Given plugins/os, when facts are generated, then no calls entry appears in io.
  9. Given system-model generation for a target, when it finishes, then the output directory holds one facts data file with an entry per class, and each entry carries io, entry?, routes_to, holds_state?, and calls.

Owner sketch

OsSdlc::SystemModel::ClassFacts (value), OsSdlc::SystemModel::Extractor and its ledger and scan collaborators (fill it), OsSdlc::SystemModel::Writer (writes the facts file).

Origin

  • Trigger: /os-sdlc:implement 1403, implementation 176; contract-auditor commit message "field-scope gaps reported"
  • Improvised this session: none
  • Chain: #1404 lacks facts ← ClassFacts has only io ← #1403 acceptance criteria tested only io ← DESIGN (ticket #1403 body)
  • Root candidate: none found; searched ClassFacts, routes_to, holds_state
  • Where: plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb
  • Session: 6c6b6eae-4ebd-4ac4-9b32-535875a6b39b
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-fast-batch-15/6c6b6eae-4ebd-4ac4-9b32-535875a6b39b.jsonl
  • Criteria rewritten 2026-10-27 (session 47f54f99): one criterion per Approach item, after #1403 built only the field its criteria tested.

Blocks: #1404

VERDICT: CREATE

## Problem #1403 shipped `ClassFacts` with one field, `io`, and `pure?`. The #1403 Approach listed six fields: `io`, `pure?`, `entry?`, `routes_to`, `holds_state?`, `calls`. Its acceptance criteria tested only `io`, so the pipeline built only `io`. #1404 writes the pattern catalog as Role predicates over these facts. The Layers, Command, and Ports-and-adapters predicates need `entry?`, `routes_to`, `holds_state?`, and `calls`. ## Reproduce ``` cat plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb ``` Output: `ClassFacts = Data.define(:io)`, with `pure?` and `merge` only. ## Approach Add the four missing fields to `ClassFacts`, fill each one in the extractor, and write the facts as data in the generated output. Definitions are in `docs/system-design-format/pattern-matching.md` section 2: * `entry?`: the class is called from `bin/*`, a hook, or a task. A Thor CLI class that a `bin/` script starts is an entry. * `routes_to`: the classes this class selects between by request name (a CLI command dispatching to one command class per command). * `holds_state?`: the class assigns an instance variable outside `initialize`. * `calls`: the classes this class sends messages to. A call to another class is a `calls` edge, not I/O. The extractor today is `Extractor` plus `Extractor::IoLedger` and the Prism visitor `Extractor::IoScan`. `IoLedger#facts` builds `ClassFacts.new(io: entries)`. The writers (`Writer`, `Writer::DirectoryFile`, `Writer::JourneyFile`) emit `.c4` text only and do not write facts. One item per field; each check names a distinct symbol. Required work: 1. Add `entry?` to `ClassFacts` and fill it from `bin/*`, hook, and task callers — check: present `entry` in `plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb` 2. Add `routes_to` and fill it from request-name dispatch — check: present `routes_to` in `plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb` 3. Add `holds_state?` and fill it from instance-variable assignment outside `initialize` — check: present `holds_state` in `plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb` 4. Add `calls` and fill it from constant-receiver message sends — check: present `calls` in `plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb` 5. Write `Model#facts` as one data file in the generated output — check: present `facts` in `plugins/os-sdlc/lib/os_sdlc/system_model/writer.rb` ## Acceptance criteria One criterion per Approach item, each with a positive and a negative case where the field has one. 1. Given `plugins/os`, when facts are generated, then the facts for `Worktree::CLI` show `entry?` true. 2. Given `plugins/os`, when facts are generated, then the facts for `Handoff::Document` show `entry?` false. 3. Given `plugins/os`, when facts are generated, then the facts for `Worktree::CLI` list `Worktree::FinishCommand` in `routes_to`. 4. Given `plugins/os`, when facts are generated, then the facts for `Handoff::Document` show an empty `routes_to`. 5. Given `plugins/os`, when facts are generated, then the facts for `Worktree::FinishCommand` (assigns `@pre_merge_head` in `merge_into_base`) show `holds_state?` true. 6. Given a class with no instance variables set outside `initialize`, when facts are generated, then `holds_state?` is false. 7. Given `plugins/os`, when facts are generated, then the facts for `Handoff::CLI` list `Handoff::Store` in `calls`. 8. Given `plugins/os`, when facts are generated, then no `calls` entry appears in `io`. 9. Given `system-model` generation for a target, when it finishes, then the output directory holds one facts data file with an entry per class, and each entry carries `io`, `entry?`, `routes_to`, `holds_state?`, and `calls`. ## Owner sketch `OsSdlc::SystemModel::ClassFacts` (value), `OsSdlc::SystemModel::Extractor` and its ledger and scan collaborators (fill it), `OsSdlc::SystemModel::Writer` (writes the facts file). ## Origin - Trigger: /os-sdlc:implement 1403, implementation 176; contract-auditor commit message "field-scope gaps reported" - Improvised this session: none - Chain: #1404 lacks facts ← ClassFacts has only io ← #1403 acceptance criteria tested only io ← DESIGN (ticket #1403 body) - Root candidate: none found; searched ClassFacts, routes_to, holds_state - Where: plugins/os-sdlc/lib/os_sdlc/system_model/class_facts.rb - Session: 6c6b6eae-4ebd-4ac4-9b32-535875a6b39b - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-fast-batch-15/6c6b6eae-4ebd-4ac4-9b32-535875a6b39b.jsonl - Criteria rewritten 2026-10-27 (session 47f54f99): one criterion per Approach item, after #1403 built only the field its criteria tested. Blocks: #1404 VERDICT: CREATE
Author
Owner

Work started on branch ticket-1412 via /os-sdlc:implement (session 47f54f99).

Work started on branch ticket-1412 via /os-sdlc:implement (session 47f54f99).
Author
Owner

Resolution

Done: ClassFacts now carries io, entry?, routes_to, holds_state?, calls; FactScan/FactLedger fill them, EntryScripts detects bin/hook/task entries, Writer writes facts.json per target.

Evidence: Implementation 180 complete, commit da26a371 on branch ticket-1412; 15 dispatches, suite green twice, behavior-verifier passed all nine criteria; new tests system_model_class_facts_fields_test.rb and system_model_writer_facts_test.rb.

Follow-ups: none; the contract-auditor LENS line (A8, IoLedger/IoScan naming) was resolved in-run by the refactorer's rename to FactLedger/FactScan.

## Resolution **Done:** ClassFacts now carries io, entry?, routes_to, holds_state?, calls; FactScan/FactLedger fill them, EntryScripts detects bin/hook/task entries, Writer writes facts.json per target. **Evidence:** Implementation 180 complete, commit da26a371 on branch ticket-1412; 15 dispatches, suite green twice, behavior-verifier passed all nine criteria; new tests system_model_class_facts_fields_test.rb and system_model_writer_facts_test.rb. **Follow-ups:** none; the contract-auditor LENS line (A8, IoLedger/IoScan naming) was resolved in-run by the refactorer's rename to FactLedger/FactScan.
jared closed this issue 2026-10-27 16:14:07 +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#1412
No description provided.