Give constant names one owner: definitions, lexical resolution, and reference sites #1718
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#1718
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Knowledge of the codebase's constant names is built again in at least seven places in os-sdlc, and the copies give different answers for the same code. On the live
plugins/os-sdlc/libtree (1,181 files), the pieces differ at 1,169 of 4,724 shared reference sites. The cause is that each piece builds its own definition table: three pieces know 1,822, 1,201, and 965 names for the same tree. Two lint cops each fail to resolve about 1,160 names that exist inlib, and a cop cannot flag a name that it cannot resolve.Observed
A read-only comparison on 2026-11-12 ran
SystemModel::Extractor,Lint::ConceptCycleCheck::References,Detector::ConstructorGraph::Visitor,Detector::ErrorLineage::Definitions,Crc::Definitions,ExpectedConstants, and the copsInwardDependency::ConstantReferenceandAdapterBuiltOutsideEntry::AdapterConstanton the same tree. The reference was a static resolver that applies Ruby's lookup rule; it is not loaded Ruby.ConceptCycleCheck::Referencesresolved 4,692 of 4,717 sites correctly with 0 wrong names. The extractor missed 328 internal names. The constructor graph missed 64 and gave 1 wrong name. The two cops missed 1,169 and 1,156.At
lib/os_sdlc/crc/filing.rb:28,Result.newis the Struct at line 10. The detector and both cops resolve it toOsSdlc::Crc::Result.AdapterConstantmatches file names without case. The constantWORDresolves tocensus/word.rb(7 sites of this kind).ExpectedConstantsgave 974 names in a fresh process and 1,187 after another loader was loaded.A responsibility audit of 81 files on the same day found nine copies of the lexical-nesting rule with three behaviors (compact
module A::B, the root anchor in::Y, the superclass scope). Examples:system_model/extractor/definition.rb:15,lint/concept_cycle_check/references.rb:69,detector/constructor_graph/visitor.rb:61,cops/structural/inward_dependency/constant_reference.rb:23. On small fixtures the copies give wrong targets for::Yand for a name under compactmodule A::B; on the live tree these rule defects cause 14 of the differing sites.Reproduce
n/a: a design finding; the comparison script was a scratch file of the session and is not in the repository.
Approach
Not decided. The owner must rule on these points before a code ticket exists:
OsSdlc::Constants, or another name such asConstantNames.inward,effects,params,calls,flay,reek) must measure the target project.The audit proposes
OsSdlc::Constantswith three parts.Constants::Nestingholds Ruby's lookup rule on plain strings, so that the RuboCop cops can share the rule and stay on the RuboCop tree (the memodocs/crc/os-sdlc/detector-cop-memo.mdadvised against a move of the cops onto Prism).Constants::Definitionsholds each definition site with name, kind, path, and line, and every file of a reopened class.Constants::Referencesholds each reference site with written name, nesting, path, line, and kind.ExpectedConstantsstays the owner of the Zeitwerk expected-file table. Each caller keeps its own policy for a name that does not resolve.Required work: none beyond the acceptance criteria.
Origin
detector/parameter_types/argument_type.rb:39) ← DESIGN (docs/system-design-format/README.md:242records that the system model was built new because the detector was bound to os-sdlc source sets)plugins/os-sdlc/lib/os_sdlc/system_model/extractor/,lint/concept_cycle_check/references.rb,detector/constructor_graph/visitor.rb,detector/error_lineage/,crc/definitions.rb,cops/structural/inward_dependency/constant_reference.rbVERDICT: CREATE
REASON: This is an observed failure that the session did not cause. The comparison showed 1,169 of 4,724 shared reference sites resolved differently, with wrong names such as
Result.newatcrc/filing.rb:28. The Origin chain ends in DESIGN, not IMPROVISATION. No open ticket has the same mechanism. #1118 and #1087 are different faults.Evidence files, copied from the session scratchpad on 2026-11-12:
/home/jared/dev/house-explore-replay/pilot10/constant-names-2026-11-12/.resolvers/report.txtis the full comparison output;resolvers/run.rb,truth.rb, andanalyze.rbmake it again.audit-probes/holds the fixtures and probe scripts of the responsibility audit. The directory is outside this repository and has no version control.Ruling by Jared, 2026-11-12, on the first checkbox (domain name): the name is
OsSdlc::SymbolIndex, notOsSdlc::Constants. His words: "Constants feels like an incredibly generic and useless name. If showed this codebase to another developer, would they immediately know the purpose and function of Constants?" and then "SymbolIndex is much better". Read eachConstants::...name in the body as follows:Constants::DefinitionsisSymbolIndex::Definitions;Constants::ReferencesisSymbolIndex::References;Constants::NestingisSymbolIndex::LexicalScope(this third name is the session's proposal; Jared ruled on the parent name only). Intended use:SymbolIndex.of(root).definitions_of(name),references_to(name),resolve(written, at: site). The other three checkboxes stay open.Rulings recorded 2026-11-12 in
docs/decisions/rulings.tsv, rows 141-144. Row 141 (Jared): the name isOsSdlc::SymbolIndex. Rows 142-144 are predictions by /os-me:predict at confidence 74, applied by the session and open to correction by Jared. Row 142: system-model collaborator edges may change where the present rule is wrong; element ids stay byte-identical; record the before and after edge diff. Row 143: the scope of the six os-sdlc-only detector sources is not part of this ticket and gets its own ticket. Row 144: start now in a worktree;SymbolIndex::Definitionsis the first increment, because the tables cause 1,169 of the differing sites and the rule defects cause 14; build the lexical-scope rule only as far asDefinitionsneeds it.Follow-up not filed (ticket-skeptic VERDICT: DROP): "Rule whether the six os-sdlc-only detector sources measure the target project". REASON: The need is speculative. Nobody has run the detector on a second project, and
docs/system-design-format/README.md:242already records that the detector is bound to os-sdlc source sets. The parent #1718 is an AI-created follow-up, so the depth-1 limit applies. Ruling 143 is only a predicted ruling, not a user request, and no security or data-loss floor applies. If a second target ever appears, file the ticket then.Decompose, phase Decide (2026-11-12). a. One change: one table of definition sites,
OsSdlc::SymbolIndex::Definitions, built once from the parsed files of a root; each caller reads it and stops building its own. It removes the cause of 1,169 of the 4,724 differing reference sites. b. Owner: no existing object owns this data.Lint::ConceptCycleCheck::Referenceshas the most complete name set (1,822 names) but keeps no file or line;Crc::Definitionskeeps every file but reads one file at a time and resolves nothing;SystemModel::Extractorkeeps only the first file of a reopened class. New object:SymbolIndex::Definitions; its secret is how a definition site is found and named (class, module, constant write,Data.define,Struct.new, reopened class, root anchor). c. Routing: step b names a new object and the ticket touches more than one sub-system (system model, lint, detector, crc), so this ticket goes to/os-sdlc:ticket-takedown 1718. Takedown writes the Owner sketch. No new investigation agents ran in this phase: the evidence is the resolver comparison and the responsibility audit of the same day (/home/jared/dev/house-explore-replay/pilot10/constant-names-2026-11-12/). Constraints for takedown, from rulings 141-144 (commit50545d495): nameOsSdlc::SymbolIndex;Definitionsis the first increment, with the lexical-scope rule only as far as it needs; first caller to move isLint::ConceptCycleCheck::References, then one caller per ticket; system-model element ids stay byte-identical (ADR-0300) and the edge diff is recorded; work in a worktree; detector source scope is out.Split by Jared, 2026-11-12 (rulings 145 and 146). The owner is now
OsSdlc::CodeShape(replacesSymbolIndex, row 141), because it will also own other duplicated Prism/AST code. Takedown run1718-20261112-160038failed green-suite: each design moved one caller and the grader wanted all callers moved. Children: #1729 CodeShape core + ConceptCycleCheck::References (blocks the rest except #1737); constant-name callers #1730 ErrorLineage, #1731 SystemModel::Extractor, #1732 ConstructorGraph/Holders + in-file constants, #1733 Crc/ArgumentType, #1734 cops lexical scope + AdapterConstant file-name match, #1735 ExpectedConstants load order, #1736 constant-node-to-name; other AST jobs #1737 tree flatten walks, #1738 method-definition collection, #1739 call-site collection, #1740 parse once per process.Added child #1741: CodeShape::Definitions. The #1729 design built only CodeShape::LexicalScope; #1730-#1733 also wait for #1741.