From 7e9f75581ab2bef02073083c7e22a6f53b8dd9db Mon Sep 17 00:00:00 2001 From: Norbert Hartl Date: Mon, 21 Sep 2026 13:03:56 +0200 Subject: [PATCH 1/3] A server image loads what it serves BaselineOfHOP declared no groups, so Metacello's default group was every package there is - and apptive-common asks for this baseline without naming one. HOP-Core-Tests, HOP-Extra-Tests and HOP-Roassal therefore travelled into apptive-base, apptive-account and apptive-metabase, none of which serve any of them. Checked in image [a]: it carries HOP-Core-Tests and HOP-Roassal today. Test classes in a deployed image are not idle. AGTestRunnerHandler hangs under #health in two of those servers and runs the whole suite of any TestCase class it is asked for, which is how a test could empty the Canopy tree a running server serves - the same finding, from the other end. HOP-Roassal does not belong there twice over: it names RSTreeLayout and its kin, which this baseline never loads, so it has been compiling against undeclared variables wherever it landed. Nothing downstream calls it - no repository under 2denker names a class from any of the three packages, nor HOPNode>>children, #displayLabel or #numberOfChildren, the three the Roassal extension adds. CI keeps loading everything. 'All' is exactly the package set the baseline had before, and .smalltalk.ston now names it, so the test run is unchanged - without that line the new default would have quietly stopped running the tests. Resolved in image [a] rather than assumed: default -> Core -> HOP-Core, HOP-Extra; All -> Core, Tests, Roassal; Tests -> the two test packages. Co-Authored-By: Claude Opus 5 (1M context) --- .smalltalk.ston | 1 + source/BaselineOfHOP/BaselineOfHOP.class.st | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.smalltalk.ston b/.smalltalk.ston index 1c8f5e0..2157947 100644 --- a/.smalltalk.ston +++ b/.smalltalk.ston @@ -4,6 +4,7 @@ SmalltalkCISpec { #baseline : 'HOP', #platforms : [ #pharo ], #directory : 'source', + #load : [ 'All' ], #onConflict : #useIncoming } ] diff --git a/source/BaselineOfHOP/BaselineOfHOP.class.st b/source/BaselineOfHOP/BaselineOfHOP.class.st index 868cbae..e2fca53 100644 --- a/source/BaselineOfHOP/BaselineOfHOP.class.st +++ b/source/BaselineOfHOP/BaselineOfHOP.class.st @@ -7,6 +7,18 @@ Class { { #category : 'baselines' } BaselineOfHOP >> baseline: spec [ + "Groups, so that an image loads what it serves. Without any, Metacello's default group is + every package there is, and apptive-common asks for this baseline without naming one - so + HOP-Core-Tests, HOP-Extra-Tests and HOP-Roassal travelled into apptive-base, + apptive-account and apptive-metabase, which serve none of them. + + Test classes in a deployed image are not idle: AGTestRunnerHandler hangs under #health in + two of those servers and runs the whole suite of any TestCase class it is asked for. + HOP-Roassal does not even belong there twice over - it names Roassal classes this baseline + never loads, so it has been compiling against undeclared variables wherever it landed. + + 'All' is what CI loads and is the package set this baseline had before the groups; nothing + about the test run changes." spec for: #'common' do: [ self @@ -23,7 +35,14 @@ BaselineOfHOP >> baseline: spec [ package: 'HOP-Extra-Tests' with: [ spec requires: #('HOP-Extra') ]; package: 'HOP-Roassal' with: [ - spec requires: #('HOP-Core') ] ] + spec requires: #('HOP-Core') ]. + + spec + group: 'Core' with: #('HOP-Core' 'HOP-Extra'); + group: 'Tests' with: #('HOP-Core-Tests' 'HOP-Extra-Tests'); + group: 'Roassal' with: #('HOP-Roassal'); + group: 'All' with: #('Core' 'Tests' 'Roassal'); + group: 'default' with: #('Core') ] ] { #category : 'as yet unclassified' } From 8309411264d00176a895daa75e8404fca95c2f7f Mon Sep 17 00:00:00 2001 From: Norbert Hartl Date: Mon, 21 Sep 2026 13:10:46 +0200 Subject: [PATCH 2/3] The Core group names the two projects as well My own regression from the commit before, and the CI caught it: HOPRouteHanderWrapperTest failed on an undeclared NeoJSONWriter, which arrives with JSONSchema. Without any group, Metacello's default group is everything the baseline mentions, and that included the two project references. A named group is a list, and a list that leaves them out leaves them out - so 'Core' loaded HOP-Core and HOP-Extra and neither JSONSchema nor Zinc, which HOP-Core needs in HOPRequestParameter and in HOPJsonResponseFormatter. Resolved in image [a]: Core -> JSONSchema, ZincHTTPComponents, HOP-Core, HOP-Extra. Co-Authored-By: Claude Opus 5 (1M context) --- source/BaselineOfHOP/BaselineOfHOP.class.st | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/BaselineOfHOP/BaselineOfHOP.class.st b/source/BaselineOfHOP/BaselineOfHOP.class.st index e2fca53..f192479 100644 --- a/source/BaselineOfHOP/BaselineOfHOP.class.st +++ b/source/BaselineOfHOP/BaselineOfHOP.class.st @@ -18,7 +18,12 @@ BaselineOfHOP >> baseline: spec [ never loads, so it has been compiling against undeclared variables wherever it landed. 'All' is what CI loads and is the package set this baseline had before the groups; nothing - about the test run changes." + about the test run changes. + + The two projects belong in a group as much as the packages do. Without any group they came + along because the default group is everything the baseline mentions; named groups are a + list, and a list that leaves them out leaves them out - HOP-Core reaches for JSONSchema in + HOPRequestParameter and for Zinc all over, so Core names both." spec for: #'common' do: [ self @@ -38,7 +43,7 @@ BaselineOfHOP >> baseline: spec [ spec requires: #('HOP-Core') ]. spec - group: 'Core' with: #('HOP-Core' 'HOP-Extra'); + group: 'Core' with: #('JSONSchema' 'ZincHTTPComponents' 'HOP-Core' 'HOP-Extra'); group: 'Tests' with: #('HOP-Core-Tests' 'HOP-Extra-Tests'); group: 'Roassal' with: #('HOP-Roassal'); group: 'All' with: #('Core' 'Tests' 'Roassal'); From c78a2d626654dee95607c46b119ffa3bd214a0cf Mon Sep 17 00:00:00 2001 From: Norbert Hartl Date: Mon, 21 Sep 2026 13:12:23 +0200 Subject: [PATCH 3/3] STONJSON instead of Neo-JSON, so HOP-Core stops reaching past its baseline Norbert, on reading the undeclared NeoJSONWriter in the CI log: we should be using STON instead. He is right, and the reason is not taste - BaselineOfHOP never declared Neo-JSON at all. It came along behind JSONSchema, so HOPJsonResponseFormatter worked by accident of load order, and the first load that did not bring JSONSchema read an undeclared variable. STON-Core is in the image Pharo ships, so there is nothing to declare. The wire format does not move. STONJSON toStringPretty: and NeoJSONWriter toStringPretty: write the same characters for this payload, and each reads the other's output - checked in image [a] before changing anything. HOP-Core-Tests 25 passed both before and after, and HOPRouteHanderWrapperTest 3 passed. HOPTestCase>>parseResponse: reads with STONJSON for the same reason, and HOPCodeTest's list of valid dependent packages gains STON-Core so it describes what HOP-Core actually uses. That test begins with #skip, so the list is documentation - but wrong documentation is worse than none. Co-Authored-By: Claude Opus 5 (1M context) --- source/HOP-Core-Tests/HOPCodeTest.class.st | 1 + source/HOP-Core-Tests/HOPTestCase.class.st | 2 +- source/HOP-Core/HOPJsonResponseFormatter.class.st | 10 +++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/source/HOP-Core-Tests/HOPCodeTest.class.st b/source/HOP-Core-Tests/HOPCodeTest.class.st index 388e87e..cefb046 100644 --- a/source/HOP-Core-Tests/HOPCodeTest.class.st +++ b/source/HOP-Core-Tests/HOPCodeTest.class.st @@ -58,6 +58,7 @@ HOPCodeTest >> validDependentPackages [ 'JSONSchema-Core' 'Kernel' 'Kernel-CodeModel' + 'STON-Core' "spec is a dependency because of the inspections" 'Spec2-Core' 'Zinc-HTTP' diff --git a/source/HOP-Core-Tests/HOPTestCase.class.st b/source/HOP-Core-Tests/HOPTestCase.class.st index 5d2c297..86b91a6 100644 --- a/source/HOP-Core-Tests/HOPTestCase.class.st +++ b/source/HOP-Core-Tests/HOPTestCase.class.st @@ -17,7 +17,7 @@ HOPTestCase >> delegate [ { #category : 'as yet unclassified' } HOPTestCase >> parseResponse: aZnResponse [ - ^ NeoJSONReader fromString: aZnResponse contents + ^ STONJSON fromString: aZnResponse contents ] { #category : 'tests' } diff --git a/source/HOP-Core/HOPJsonResponseFormatter.class.st b/source/HOP-Core/HOPJsonResponseFormatter.class.st index 3704350..2dcb525 100644 --- a/source/HOP-Core/HOPJsonResponseFormatter.class.st +++ b/source/HOP-Core/HOPJsonResponseFormatter.class.st @@ -7,7 +7,15 @@ Class { { #category : 'formatting' } HOPJsonResponseFormatter >> format: responseObject [ - ^ ZnStringEntity json: (NeoJSONWriter toStringPretty: { + "STONJSON rather than NeoJSONWriter, and the reason is not taste: HOP-Core reached for a + class its own baseline never declared. Neo-JSON came along behind JSONSchema, so the day a + load did not bring JSONSchema this method read an undeclared variable - which is exactly + how it showed up. STON-Core is in the image Pharo ships. + + The wire format does not move. Checked against the same payload: STONJSON toStringPretty: + and NeoJSONWriter toStringPretty: write the same characters, and each reads the other's + output." + ^ ZnStringEntity json: (STONJSON toStringPretty: { #code -> responseObject statusCode. #type -> responseObject exceptionType. #message -> responseObject hopMessageObject