Spec reference
x-FuSa spec §4, Path relativity (MUST):
location.file MUST be a path relative to projectRoot (the --dir value), using / separators — never an absolute path.
§9.2 fmea.json: "file": "src/rules.go", // MUST. project-relative (§4 rule). §9.2 tara.json: "location": { "file": "…", "line": 42 }. §9.3 sci.json: "artifacts": [ { "file": "src/main.go", ... } ].
What actually happens
fmea.json / tara.json — basename only, not project-relative
This repo's own committed fmea.json/tara.json show only the basename, discarding the directory:
{"item": "cmd_coupling", "file": "cmd_coupling.c", "line": 121, ...}
The real project-relative path is cmd/cfusa/cmd_coupling.c (confirmed: find . -name cmd_coupling.c → ./cmd/cfusa/cmd_coupling.c). This is deliberate, not incidental — cmd/cfusa/cmd_tara.c's write_threat_json() explicitly does:
" \"location\": {\"file\": \"%s\", \"line\": %d}\n"
...
cfusa_basename(a->file), a->line, last ? "" : ",");
and cmd_fmea.c's equivalent JSON writer does the same.
sci.json — absolute path when --dir is absolute
$ cfusa sci --dir /Users/matt/Documents/Coding/SoundMatt/c-FuSa --format json --output sci.json
$ python3 -c "import json; print(json.load(open('sci.json'))['artifacts'][0])"
{'file': '/Users/matt/Documents/Coding/SoundMatt/c-FuSa/cmd/cfusa/cmd_pr.c', 'hash': 'sha256:1f0b...', 'version': '0.5.1'}
For comparison, check handles the identical --dir <absolute-path> case correctly — its location.file is properly relativized even though projectRoot (correctly, per §3.2) is the absolute --dir value:
$ cfusa check --dir /Users/matt/Documents/Coding/SoundMatt/c-FuSa --format json
"projectRoot": "/Users/matt/Documents/Coding/SoundMatt/c-FuSa"
"findings":[{"location":{"file":"cmd/cfusa/cmd_qualify.c","line":473}, ...}]
So sci (new in this PR's schema-conformance pass) is a regression relative to the relativization logic check already gets right elsewhere in the same binary.
Why this matters
Both are the exact failure mode §4 exists to prevent: fingerprints/paths that aren't stable/comparable across machines and tools, and (for sci specifically) real information leakage of local filesystem layout into an artifact meant to be portable evidence.
Suggested fix
fmea/tara: emit a->file/fn->file (already stored relative-to---dir) directly instead of running it through cfusa_basename() for the JSON file/location.file fields (basename is fine for the human-readable failureMode/asset/threat prose text, just not for the structured path field).
sci: relativize artifacts[].file against the resolved --dir the same way check already does, regardless of whether --dir was given as an absolute or relative path.
Spec reference
x-FuSa spec §4, Path relativity (MUST):
§9.2
fmea.json:"file": "src/rules.go", // MUST. project-relative (§4 rule). §9.2tara.json:"location": { "file": "…", "line": 42 }. §9.3sci.json:"artifacts": [ { "file": "src/main.go", ... } ].What actually happens
fmea.json / tara.json — basename only, not project-relative
This repo's own committed
fmea.json/tara.jsonshow only the basename, discarding the directory:{"item": "cmd_coupling", "file": "cmd_coupling.c", "line": 121, ...}The real project-relative path is
cmd/cfusa/cmd_coupling.c(confirmed:find . -name cmd_coupling.c→./cmd/cfusa/cmd_coupling.c). This is deliberate, not incidental —cmd/cfusa/cmd_tara.c'swrite_threat_json()explicitly does:and
cmd_fmea.c's equivalent JSON writer does the same.sci.json — absolute path when --dir is absolute
For comparison,
checkhandles the identical--dir <absolute-path>case correctly — itslocation.fileis properly relativized even thoughprojectRoot(correctly, per §3.2) is the absolute--dirvalue:So
sci(new in this PR's schema-conformance pass) is a regression relative to the relativization logiccheckalready gets right elsewhere in the same binary.Why this matters
Both are the exact failure mode §4 exists to prevent: fingerprints/paths that aren't stable/comparable across machines and tools, and (for
scispecifically) real information leakage of local filesystem layout into an artifact meant to be portable evidence.Suggested fix
fmea/tara: emita->file/fn->file(already stored relative-to---dir) directly instead of running it throughcfusa_basename()for the JSONfile/location.filefields (basename is fine for the human-readablefailureMode/asset/threatprose text, just not for the structured path field).sci: relativizeartifacts[].fileagainst the resolved--dirthe same waycheckalready does, regardless of whether--dirwas given as an absolute or relative path.