chameleon 2.38.14
Real-world QA pass across the sibling-context, cross-file existence, and
conformance + comprehension surfaces. Every fix was reproduced and verified
against real bootstrapped repos through the real hooks, tools, and MCP stdio
transport, and re-checked after the fix.
Fixed
- A control byte in a sibling filename could split the single-line "Nearby:"
listing. A source filename never legitimately contains a newline / CR / tab
(POSIX allows any byte but/and NUL), but a hostile or corrupt name that did
flowed unscrubbed into the per-edit sibling listing, breaking it into multiple
lines with attacker-controlled text on its own line. The listing and the nearby
collaborator-signatures path now strip control bytes from display names. - The live cross-file reference check flagged a clean rename refactor as a
broken call site. The "you removed export X, still imported by Y" advisory
(and theget_crossfile_context/query_symbol_importerstools) matched the
removed name as a bounded substring of the importer's module path (apiinside
'@/lib/api-client'), so an importer that fully renamed its reference was still
reported as referencing the old name. The presence check now blanks string
literals before the scan; a genuine named-import reference is anchored by the
import binding, so this only drops the false match. Left the Ruby constant path
string-inclusive (its interpolating strings carry real references, and it has no
import binding to anchor a code-only scan). - Degraded-state honesty across the comprehension + read tools. A damaged,
corrupt, or untrusted profile must degrade honestly, never crash, lie, or assert
a false affirmative from an unknown:get_canonical_excerptandget_rulesraised on a structurally-malformed
(but generation-valid)canonicals.json/rules.json; the crash sat before
the trust gate, so an untrusted profile could trigger it. Both now guard the
inner structure and degrade.describe_codebasereported a generation-mismatched profile as an empty
codebase (contradictingsearch_codebaseover the same profile) because a
profile-bundle validation failure discarded the independent symbol index. It
now reports the real file/symbol totals with adegradedflag.get_drift_statusfabricated "production branch moved" when the derivation
SHA was merely unreadable, and reported "profile is fresh" for a corrupt
profile.json. It now omits the claim on an unknown SHA and surfaces
derivation_unknown.- A corrupt
conventions.jsonsilently dropped the healthyprinciples.md
PRINCIPLES + ANTI-HALLUCINATION PROTOCOL for the whole session at
SessionStart.principles.mdis now read independently of the conventions
parse. get_calleesreturnedfound: trueechoing a non-stringfunction_name;
it now guards the argument like its sibling call-graph tools.
- A multi-witness archetype lost all witness guidance when the selected witness
was deleted. The per-edit block flagged the whole archetype's witness as
missing even though live sibling witnesses of the same archetype remained on
disk. It now falls through to the nearest live witness, and the "mirror the
canonical witness" lead is suppressed when no witness excerpt is present. - A poisoned committed profile could inject a forged spotlight marker into a
trusted directive. Aclass_contract/key_exportsvalue rendered as a
chameleon directive (outside the untrusted spotlight) could carry a forged
[chameleon-untrusted-data:...]boundary marker plus a newline into trusted
text. The boundary sanitizer now breaks the marker for every render path, and
archetype-facts values are stripped of control bytes. - Python
key_exportslisted imports as things to "reuse before creating a new
one". The Python path reused the importable-name set (built for the
phantom-symbol existence check), which folds in every module-level import, so
the anti-duplication directive advertisedos,json,models,User, ...
as archetype exports and crowded real classes past the display cap. It now
subtracts import locals, matching the TypeScript (export-only) and Ruby
(class/module) sets. Takes effect on the next/chameleon-refresh.