[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.
Kind: refactor. Source: review Part 5.4 ("Go") and Part 6.4 (manifest table), register E19 (Go half).
Problem
The go.mod module directive has two hand-written readers (rows 1 and 2 below), and neither uses the directive walker that go_mod_edit already shares with the hosted rewriter and VEX discovery. Verified on 045d7ec:
| Reader |
Production callers |
Grammar |
crawlers/go_crawler.rs parse_go_mod_module |
none. grep -rnw over the workspace, including socket-patch-node, finds it only in its own unit tests and tests/crawler_go_e2e.rs. Its last caller went away before 2463257. |
first whitespace token; no BOM handling; no path-safety check |
vex/product.rs parse_go_mod |
VEX --product auto-detection (the PRODUCT_MANIFESTS probe at product.rs#L83) |
strips a BOM; rejects module foo bar; runs is_safe_multi_segment |
go_mod_edit for_each_directive_body / directive_body,`` with normalize_for_read |
require and replace for hosted, vendored, agent apply and VEX |
single-line and keyword ( … ) block forms, quoted tokens, any whitespace |
They have drifted, proven by execution. Go accepts the block form of the directive: with go.mod = module (⏎\texample.com/blk⏎)⏎⏎go 1.21, go 1.24.7 list -m prints example.com/blk. A unit probe on the same text, run twice on 045d7ec (not committed), got:
product::parse_go_mod → Some("pkg:golang/(")
go_crawler::parse_go_mod_module → Some("(")
- control
module example.com/m → both example.com/m
go_mod_edit's walker already handles the block form, because it is the same rule it uses for require ( … ).
Symptoms and impact
I found no open issue for this. A block-form module directive is rare, so the user-visible risk is low (a wrong --product purl on a valid project). The structural cost is a dead public function with two test files pinning it, and a third copy of go.mod lexing that will drift again whenever the shared walker changes.
Proposed change
- Add
go_mod_edit::module_path(text: &str) -> Option<String> built on normalize_for_read + for_each_directive_body(text, "module", …): the first body's first token, unquoted, rejected when empty or when is_safe_multi_segment fails.
- Make
vex/product.rs parse_go_mod call it and keep only the pkg:golang/<module> formatting.
- Delete
crawlers::go_crawler::parse_go_mod_module and its tests. Move the cases worth keeping (quoted path, module "", trailing comment, modulepath = x, module foo bar) to go_mod_edit's unit tests, and drop the parse_go_mod_module import from tests/crawler_go_e2e.rs.
Size and scope
vendor/go_mod_edit.rs (+15), vex/product.rs (−15), crawlers/go_crawler.rs (−45 prod, −35 test), tests/crawler_go_e2e.rs (−~30). Roughly −45 production lines net. Out of scope: moving go_mod_edit into formats/ (E20; #631 does this for go_sum_edit), and the other manifest probes in product.rs (E38).
Acceptance criteria
Dependencies
None; it can start now. If #631 lands first and moves the go codecs into formats/golang/, put module_path next to the go.mod reader wherever it lives then.
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.
Kind: refactor. Source: review Part 5.4 ("Go") and Part 6.4 (manifest table), register E19 (Go half).
Problem
The go.mod
moduledirective has two hand-written readers (rows 1 and 2 below), and neither uses the directive walker thatgo_mod_editalready shares with the hosted rewriter and VEX discovery. Verified on045d7ec:crawlers/go_crawler.rsparse_go_mod_modulegrep -rnwover the workspace, includingsocket-patch-node, finds it only in its own unit tests andtests/crawler_go_e2e.rs. Its last caller went away before2463257.vex/product.rsparse_go_mod--productauto-detection (thePRODUCT_MANIFESTSprobe atproduct.rs#L83)module foo bar; runsis_safe_multi_segmentgo_mod_editfor_each_directive_body/directive_body,`` withnormalize_for_readrequireandreplacefor hosted, vendored, agent apply and VEXkeyword ( … )block forms, quoted tokens, any whitespaceThey have drifted, proven by execution. Go accepts the block form of the directive: with
go.mod=module (⏎\texample.com/blk⏎)⏎⏎go 1.21,go 1.24.7 list -mprintsexample.com/blk. A unit probe on the same text, run twice on045d7ec(not committed), got:product::parse_go_mod→Some("pkg:golang/(")go_crawler::parse_go_mod_module→Some("(")module example.com/m→ bothexample.com/mgo_mod_edit's walker already handles the block form, because it is the same rule it uses forrequire ( … ).Symptoms and impact
I found no open issue for this. A block-form
moduledirective is rare, so the user-visible risk is low (a wrong--productpurl on a valid project). The structural cost is a dead public function with two test files pinning it, and a third copy of go.mod lexing that will drift again whenever the shared walker changes.Proposed change
go_mod_edit::module_path(text: &str) -> Option<String>built onnormalize_for_read+for_each_directive_body(text, "module", …): the first body's first token, unquoted, rejected when empty or whenis_safe_multi_segmentfails.vex/product.rsparse_go_modcall it and keep only thepkg:golang/<module>formatting.crawlers::go_crawler::parse_go_mod_moduleand its tests. Move the cases worth keeping (quoted path,module "", trailing comment,modulepath = x,module foo bar) togo_mod_edit's unit tests, and drop theparse_go_mod_moduleimport fromtests/crawler_go_e2e.rs.Size and scope
vendor/go_mod_edit.rs(+15),15),vex/product.rs(−crawlers/go_crawler.rs(−45 prod, −35 test),tests/crawler_go_e2e.rs(−~30). Roughly −45 production lines net. Out of scope: movinggo_mod_editintoformats/(E20; #631 does this forgo_sum_edit), and the other manifest probes inproduct.rs(E38).Acceptance criteria
parse_go_mod_moduleno longer exists.grep -rn 'strip_prefix("module")' cratesfinds nothing outside tests.module_path: single-line, quoted, trailing//comment, BOM, block formmodule ( … ), emptymodule "",module foo bar(→None),modulepath = x(→None), unsafe segments (→None).vex/product.rstest: a block-form go.mod yieldspkg:golang/example.com/blk.cargo test -p socket-patch-core(includingcrawler_go_e2e) and thevexproduct tests stay green.Dependencies
None; it can start now. If #631 lands first and moves the go codecs into
formats/golang/, putmodule_pathnext to the go.mod reader wherever it lives then.