Repository navigation
shape-doctor.py's manifest row says ok ... passes when the project's own validate-manifest.py exits 0 after printing WARNING naming-referent-chain: ... not reachable here, and the warning appears nowhere in the text or --json report, so a referent chain nothing on this disk could check reads as checked under COMPLIANT: the class of the skip #357 makes a note, in the form #357 still drops #448
Description
Lane: openreposhape-4 (openRepoShape-4)
Found by this lane's adversarial review of #278, #297 and #298 (PR #357, head 2bf402d, its N2): "WARNING lines on exit 0 are still dropped ... It is the same class as the skip, but no issue or ruling covers it." PR #357's body carries it as follow-up N2 at its head 8ad856f. #357 landed as 5678f68. Before it, main 3ae0109 dropped these lines and the skip lines both. #357 turned a skip into a note and still drops a WARNING. Verified on main at 5678f68. Local bare remotes, an empty global git config, GIT_ALLOW_PROTOCOL=file, and a gh that exits 97 (only the machine row calls it; the validator's own gh api for the openXdox pin gets the same answer, so since #357 landed the pins row is a note here as well). Not claimed: macOS and Windows, which were not run.
What is wrong.
validate-manifest.pyprints aWARNINGline and exits 0 when a recorded referent chain has a link whose tree is not on this disk. Its words: "A WARNING is a note about what could not be CHECKED here ... It is printed and then forgotten by the exit code, deliberately" (templates/assembly-root/scripts/validate-manifest.py:720-722at 5678f68).- The doctor's
validator_row(shape-doctor.py:1392-1398at 5678f68) returnsok ... passesfor exit 0 unlessskipped()foundskipblocks. AWARNINGline ends a skip block (REPORT_ITEM,:1104-1105) and is never collected itself:
U=<openRepoShape checkout> # a clean checkout of main at 5678f68, the squash #357 landed as
# Runs in bash on Linux (GNU coreutils). Nothing leaves the machine: every repository is a local bare one under $R, git
# reads an empty global config, GIT_ALLOW_PROTOCOL=file makes any accidental https/ssh clone fail, and a `gh` that exits
# 97 stands first on PATH.
R=$(mktemp -d); mkdir $R/bin; printf '#!/bin/sh\nexit 97\n' > $R/bin/gh; chmod +x $R/bin/gh; touch $R/gitconfig
export PATH=$R/bin:$PATH GIT_CONFIG_GLOBAL=$R/gitconfig GIT_CONFIG_NOSYSTEM=1 GIT_ALLOW_PROTOCOL=file \
GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t.invalid GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t.invalid
row() { python3 -c '
import json, sys
d = json.load(open(sys.argv[1]))
for r in d["rows"]:
if r["id"] in sys.argv[2].split(","):
det = r.get("detail", {})
print(" " + r["id"] + ":", r["status"], "|", r["reason"][:120], "| crashed:", det.get("crashed"), "environment:", det.get("environment"))
print(" verdict:", d["verdict"] + ", exit", d["exit"])' "$1" "$2"; }
# openXdox is a layer that pins openDox; codexDox pins openXdox and names openDox as its referent through that chain
git init -q -b main $R/src/openXdox
printf 'schema_version: 1\nkind: project-manifest\nneutral_product_pins:\n - openDox\n' > $R/src/openXdox/project.yaml
git -C $R/src/openXdox add -A && git -C $R/src/openXdox commit -qm seed; X=$(git -C $R/src/openXdox rev-parse HEAD)
python3 $U/scaffold-project.py --org testorg --project codexDox --elected-by 'Test Human' --elected-on 2026-10-12 \
--pin openXdox@$X --pin-source $R/src/openXdox --referent-chain openXdox,openDox \
--local-remote-dir $R/remotes --work-dir $R/work >/dev/null
C=$R/away/codexDox; git clone -q --recurse-submodules $R/remotes/codexDox.git $C # no openXdox checkout beside it
(cd $C && python3 scripts/validate-manifest.py 2>&1 | cut -c1-150; echo "the root's own validate-manifest.py: exit ${PIPESTATUS[0]}")
python3 $U/shape-doctor.py --root $C --json > $C.json; echo "doctor --json: exit $?"; row $C.json manifest
python3 -c 'import json, sys; print(" WARNING anywhere in the --json report:", "WARNING" in open(sys.argv[1]).read())' $C.json
python3 $U/shape-doctor.py --root $C > $C.txt 2>&1; echo " WARNING lines in the text report: $(grep -c WARNING $C.txt)"
echo "== the same root with a FINDING after that WARNING: the spec leg's naming.role says 'code'"
D=$R/away/codexDox2; git clone -q --recurse-submodules $R/remotes/codexDox.git $D
sed -i '/form: project-leg/{n;s/role: spec/role: code/}' $D/project.yaml
(cd $D && python3 scripts/validate-manifest.py 2>&1 | grep -E '^(WARNING|FINDING)' | cut -c1-150; echo "the root's own validate-manifest.py: exit ${PIPESTATUS[0]}")
python3 $U/shape-doctor.py --root $D --json > $D.json; echo "doctor --json: exit $?"; row $D.json manifest
Output on main at 5678f68:
WARNING naming-referent-chain: leg 'assembly': declared-unverified: openXdox declaring a pin on openDox is a fact in openXdox's own tree, which is not
manifest ok: codexDox (codexdox), 3 legs
the root's own validate-manifest.py: exit 0
doctor --json: exit 0
manifest: ok | the project's own scripts/validate-manifest.py passes | crashed: None environment: None
verdict: COMPLIANT, exit 0
WARNING anywhere in the --json report: False
WARNING lines in the text report: 0
== the same root with a FINDING after that WARNING: the spec leg's naming.role says 'code'
WARNING naming-referent-chain: leg 'assembly': declared-unverified: openXdox declaring a pin on openDox is a fact in openXdox's own tree, which is not
FINDING naming-role: leg 'spec': naming.role is 'code', but 'codexDox-spec' classifies as 'spec'
the root's own validate-manifest.py: exit 1
doctor --json: exit 1
manifest: FINDING | the project's own scripts/validate-manifest.py reports a finding (exit 1): WARNING naming-referent-chain: leg 'assembly' | crashed: None environment: None
verdict: INVALID (manifest), exit 1
The validator says the chain's middle link could not be read here: "openXdox declaring a pin on openDox is a fact in openXdox's own tree, which is not reachable here (a sibling checkout, SHAPE_PIN_SOURCE_OPENXDOX, or --link-source openXdox= would let it be read)". The doctor says the gate passes, under COMPLIANT, and the word appears nowhere in its report, as text or as --json.
The same blind spot has a red twin, found by this lane's plan for the next doctor change (its R08-4): a row that is already a FINDING can quote the WARNING as its finding. run_validator quotes the first line of the output that starts FINDING, REFUSED or WARNING (shape-doctor.py:1230-1237), and validate-manifest.py prints leg by leg, so a WARNING from an earlier leg comes before a later leg's FINDING, and the row's reason is then the note that moved nothing and not the finding that failed the gate. The last lines of the repro change the spec leg's naming.role to code, a true naming-role finding, on the same root: the validator prints the WARNING and then the FINDING, and the manifest row is FINDING with the WARNING as its quoted line.
Why. #297 ruled that a check the validator could not make, which it reports and which leaves its exit at 0, is a note in the doctor's row: "passes, but did not recheck: ...", with detail.skipped. PR #357 implements that for the skip form validate-pins.py prints. validate-manifest.py reports the same kind of thing in another form, WARNING <code>: ..., and nothing reads it.
What it should do. An exit 0 that came with a WARNING line is a note naming it, as a skip is. The verdict does not move. The decisions are the author's:
- The form. Its own
detail.warningsand wording ("passes, with a warning: ..."), or folded into shape-doctor.py: a validator that crashed says it crashed instead of "reports a finding", and is CANNOT ANSWER when it is the standard's template, which a standard whose path holds thePYTHONPATHseparator no longer runs at all; a neutral product's digestvalidate-pins.pyskipped is anotenaming the product, from a child that can no longer reachghor a proxy; and a root whose manifest does not load and whosescripts/repo_shape.pyis gone is told to restore that file before its gate (#278, #297, #298) #357'sskippednote. - Which children.
validate-manifest.pyis the validator that printsWARNINGlines on exit 0 today. The naming script printsWARNINGlines on stderr for an unread link tree (scripts/validate-repository-naming.py:480-485), so thenamingrow has the same gap. The project-mode run in this repro printed none, so that row was not shown here. - NEXT. None, as for a skip, since the warning names its own remedies (a sibling checkout,
SHAPE_PIN_SOURCE_<LINK>,--link-source). - The quoted line of a red row. A suggestion from the same plan (its R08-4):
run_validatorquotes the firstFINDINGorREFUSEDline, else the firstWARNING, else the output's last line, so a row that fails never names a note as its reason.
How to test. A descendant by chain, scaffolded with --pin openXdox@<commit> --pin-source <stand-in> --referent-chain openXdox,openDox and cloned with no openXdox beside it. The manifest row is a note whose reason quotes naming-referent-chain, and the verdict is still COMPLIANT, exit 0. The control has the link's tree beside it (or SHAPE_PIN_SOURCE_OPENXDOX): the row is ok. For decision 4, the same root with a naming-role finding added: the row's reason quotes the FINDING naming-role line, not the WARNING.
Verified on main at 5678f68, the squash #357 landed as (shape-doctor.py sha256 c206264b…, validate-manifest.py 50f56a3e…).
Related: #297 / PR #357 (a skip becomes a note), #278, #447 (the same PR's other follow-up), #40 / PR #42 (the referent chain).
Activity
brettheap commentedon Oct 14, 2026
CLAIMED — lane openRepoShape-4, session 11c6c0ef-495a-4a05-94cf-811b7b0a1012@Eagle, 2026-10-14T16:52:07Z, for #448
Logged in
lanes/log/openRepoShape-4.mdat8f3123e4e63a58b5a44767b381948dad9d807daa.The three reads (lane-collision-protocol Rule 1):