Skip to content

feat: v0.36.0 — x-FuSa spec v1.13.0/v1.14.0 schema conformance + content-quality baseline - #55

Merged
SoundMatt merged 1 commit into
mainfrom
feat/xfusa-v113-v114-schema-conformance
Jul 28, 2026
Merged

feat: v0.36.0 — x-FuSa spec v1.13.0/v1.14.0 schema conformance + content-quality baseline#55
SoundMatt merged 1 commit into
mainfrom
feat/xfusa-v113-v114-schema-conformance

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

Closes #54. Brings hara/fmea/tara/safety-case/sas/sci into conformance with x-FuSa spec §9.2/§9.3's formalized schemas, and implements the new §1.6/§1.6.1/§1.6.2 content-quality baseline (detection heuristics + attestation).

Schema conformance

  • hara: .fusa-hara.json safetyGoals[].fssrRefs is now a []string (MUST, ≥1 entry), replacing the prior singular fssrRef string. New engine rules HARA006 (missing fssrRefs) and HARA007 (dangling fssrRefs id). hara show --format json now emits the §9.2 hara-report envelope + completeness block instead of the bare input file. hara init now scaffolds empty collections — never a dummy hazard (this is literally the bug the spec's audit found; go-FuSa's init had it too).
  • fmea: adds spec-canonical singular failureMode/effect/cause fields alongside the existing arrays (kept for back-compat/CSV), plus item/actionPriority/mitigations, and a summary block (componentsAnalyzed/componentsInProject/coveragePct + --min-coverage N).
  • tara: threats[] replaces entries[] as the canonical key; impact is now an SFOP object (safety/financial/operational/privacy, ISO 21434 Clause 15.7) instead of one generic string; adds attackFeasibility/risk/treatment/location + the same summary/coveragePct shape.
  • safety-case: adds a real GSN (Goal Structuring Notation v3) argument graph — nodes[]/edges[]/completeness, all six GSN node types (goal/strategy/solution/context/assumption/justification) — derived from the same evidence collection Build already assembled.
  • sas: adds checklist[]/summary; sas.md is now always written alongside sas.json regardless of which format was requested (spec: "not a replacement for it").
  • sci: adds artifacts[] (file/hash/version), hash correctly sha256:-prefixed.
  • All six now carry the §3.1 common header (schemaVersion/kind/tool/toolVersion/language/generatedAt).
  • Checked every hash-named field for the §2.7 prefix bug FuSaOps found in its own code — go-FuSa had none pre-existing; the new sci.Artifacts[].Hash field is sha256:-prefixed from the start.

Content-quality baseline (new stubcheck package)

  • FUSA-STUB001 (rule A): placeholder/template text deny-list (bracket-wrapped instructional text, "replace with", "TBD", etc.) — always ERROR, disposition-suppressible only, never by attestation.
  • FUSA-STUB002 (rule B): a qualitative field's distinct-value ratio <0.1 across ≥10 entries — WARNING by default, advisory, suppressed by a valid attestation.
  • Both run as check engine rules across every present evidence artifact (fmea.json/.fusa-hara.json/tara.json/safety-case.json/sas.json).
  • Attestation (fusa.Attestation: status/implementationAuthor/independentReviewer/reviewedAt/contentHash), fusa.AttestationValid (independence + non-staleness, fail-safe), fusa.CanonicalizeJSON (RFC 8785). All five artifact commands gain --strict/--require-attestation.

Coverage metrics

  • fmea/tara summary.coveragePct + --min-coverage N, each with an honestly-documented denominator methodology (CountProjectFunctions/CountProjectFiles, independent of the artifact's own generation pass) rather than a denominator that trivially always equals the numerator.

Housekeeping

  • Migrated the committed .fusa-hara.json's fssrRef strings to fssrRefs arrays.
  • Regenerated fmea.json/tara.json/safety-case.{json,md,mermaid} with the new schemas.
  • Registered 45 new //fusa:req tags in .fusa-reqs.json.
  • Bumped Version0.36.0, SpecVersion1.14.0.

Test plan

  • go build ./...
  • go vet ./... clean
  • gofmt -l . clean
  • golangci-lint run ./... — 0 issues
  • go test -race -count=1 ./... — all pass, 88.6% overall coverage (≥80% gate)
  • gofusa check --format json on go-FuSa's own repo — exit 0, 0 errors (self-check stays green; new FUSA-STUB002 findings on fmea.json/tara.json are WARNING-only and don't gate without --strict)
  • gofusa trace — exit 0, no dangling references for any new requirement

…ent-quality baseline

Brings hara/fmea/tara/safety-case/sas/sci into conformance with the
x-FuSa spec's formalized §9.2/§9.3 schemas, and implements the new
§1.6/§1.6.1/§1.6.2 content-quality baseline (issue #54):

- hara: safetyGoals[].fssrRefs is now a required []string (was a
  singular optional fssrRef string); new engine rules HARA006/HARA007
  catch a missing or dangling fssrRefs entry; `hara show --format json`
  emits the spec's hara-report envelope+completeness shape; `hara init`
  scaffolds empty collections instead of a dummy example hazard.
- fmea: adds singular failureMode/effect/cause fields (spec-canonical)
  alongside the existing arrays, plus item/actionPriority/mitigations
  and a summary block with componentsAnalyzed/componentsInProject/
  coveragePct (+ --min-coverage N).
- tara: threats[] replaces entries[] as the canonical key; impact is
  now an SFOP object (safety/financial/operational/privacy) instead of
  one generic string; adds attackFeasibility/risk/treatment/location
  and the same summary/coveragePct shape (+ --min-coverage N).
- safety-case: adds a real GSN argument graph (nodes/edges/completeness,
  all six GSN node types) derived from the existing evidence collection.
- sas: adds checklist[]/summary; sas.md is now always written alongside
  sas.json regardless of which format was requested.
- sci: adds artifacts[] (file/hash/version, hash sha256:-prefixed).

New stubcheck package implements FUSA-STUB001 (placeholder-text
deny-list, always ERROR, disposition-suppressible only) and
FUSA-STUB002 (distinct-value-ratio <0.1 across >=10 entries, WARNING,
advisory) as engine rules wired into `check`, plus the §1.6.2
attestation mechanism (fusa.Attestation, RFC 8785 canonical content
hash) that suppresses a non-stale, independently-reviewed
FUSA-STUB002. All five artifact commands gain --strict/
--require-attestation.

Regenerates fmea.json/tara.json/safety-case.{json,md,mermaid} and
migrates .fusa-hara.json's fssrRef strings to fssrRefs arrays.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
Comment thread tara/tara.go
// Summary.AssetInventoryMethod for the file-level-granularity caveat.
//
//fusa:req REQ-TARA008
func CountProjectFiles(root string) (int, error) {
Comment thread stubcheck/rules.go
}

func fileExists(path string) bool {
_, err := os.Stat(path)
Comment thread stubcheck/rules.go
func loadArtifacts(projectRoot string) []artifactScan {
var out []artifactScan

if _, err := os.Stat(filepath.Join(projectRoot, hara.HARAFile)); err == nil {
Comment thread stubcheck/rules.go
content interface{}
}

func loadArtifacts(projectRoot string) []artifactScan {
Comment thread hara/hara.go
// checking against it — every fssrRef then counts as dangling, fail-safe).
//
//fusa:req REQ-HARA017
func BuildCompleteness(h *HARA, reqIDs map[string]bool) Completeness {
Comment thread fusa.go
// independently of substantive edits (§1.6.2).
//
//fusa:req REQ-ATT003
func AttestationContentHash(content interface{}) (string, error) {
Comment thread stubcheck/rules.go
// unsuppressed (fail-safe).
//
//fusa:req REQ-STUB012
func AttestationSuppresses(att *fusa.Attestation, content interface{}) bool {
Comment thread stubcheck/stubcheck.go
// placeholderBracket matches bracket-wrapped instructional text such as
// "[describe asset]" — a letter immediately after '[' distinguishes this
// from e.g. Markdown link syntax or a literal array-like value.
var placeholderBracket = regexp.MustCompile(`\[[A-Za-z][^\]]*\]`)
Comment thread stubcheck/stubcheck.go
var placeholderBracket = regexp.MustCompile(`\[[A-Za-z][^\]]*\]`)

// placeholderSubstrings is the case-insensitive deny-list (§1.6.1 rule A).
var placeholderSubstrings = []string{
Comment thread fmea/fmea.go
// line ("func Name(" or "func (recv Type) Name(", uppercase first letter).
// It is intentionally a raw text scan, not an AST parse — see
// CountProjectFunctions doc.
var exportedFuncRE = regexp.MustCompile(`^func\s+(\([^)]*\)\s+)?[A-Z]\w*\s*\(`)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants