BOHICA-LABS / BOHICA-LABS/vsdd-factory
process-gap(product-owner+adversary): BC postconditions may claim behavior downstream of the software boundary (ecosystem-observable, not product-testable)
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
## Process-gap
A behavioral contract's postcondition can be phrased as a consequence that only manifests **outside** the software under test — a protocol-library or OS-level observable that the product neither implements nor mediates. The AC is technically-true (the downstream observable does occur), but "testing" it either (a) tests the third-party library instead of the product, or (b) requires a fixture that recreates the external environment purely to observe an effect the product does not cause.
## Concrete shape (sanitized)
A BC governing a CLI activation surface listed a postcondition of the form: "attempt to use socket → downstream client returns \`CLIENT_FAILURE\`." The activation surface writes a socket path; the failure is emitted by an unrelated third-party client after that client attempts to connect to the (broken) socket. The product neither returns the failure nor participates in emitting it. Adversary Pass-1 flagged the anchor scope. Product-owner then narrowed the BC to "product-layer only: the activation surface produces a well-formed export line and terminates 0 or 1; the SSH-client observable is an ecosystem consequence, not a product postcondition."
## Why existing gates miss it
- \`bc_traces\` links are checked (issue #400 addresses PC-granularity); scope-boundary is not checked at all.
- Consistency-validator sees the AC citing a real BC PC; it can't reason about whether the PC *should* have been in the BC.
- Test-writer will happily construct an environment-fixture to produce the downstream observable; the test compiles, runs, and passes — but tests the ecosystem library, not the product.
- Adversary catches it only when it thinks explicitly about the software boundary, which is not a listed policy check.
## Distinct from adjacent issues
- **#388** (orphaned integration seam) — different: that's a wiring seam nobody owns; this is a postcondition that no code inside the product will ever satisfy because the responsibility lives outside the boundary.
- **#400** (AC↔BC PC-level trace table) — different: that's mis-anchoring within a valid BC; here the BC itself over-reaches.
- **#391** (mis-anchor severity) — different axis (severity of a mis-anchor vs. detection of scope-overreach).
- **#375** (sentinel value without derived-field enumeration) — different: that's under-specification; this is over-scoping.
## Proposed remediation
1. **product-owner** dispatch checklist gains: "for each PC/postcondition, name the specific product-owned code path that satisfies it. If the satisfier is an external library, OS behavior, or client protocol — the PC belongs in an ecosystem/contract-boundary document, not the BC."
2. **adversary** policy list gains a scope-boundary check (paraphrased): "does every BC postcondition name a behavior that the software-under-test *causes*, as opposed to a behavior *observable in the environment when the software runs*? If the latter, flag IMPORTANT."
3. **spec-reviewer** early-cycle check (cheap): for each PC, ask "which product file will contain the code that satisfies this?" If the answer is "none — it's a client library's response," escalate.
## Impact
Not caught early, a scope-overreach postcondition either (a) blocks story convergence until a narrowing decision is made, or (b) produces a test that green-lights the external library and later regresses when the library changes — a false-positive that hides a real integration gap. The narrowing came late in an adversarial cycle; earlier detection is a cheap policy addition.
## Severity
MEDIUM. Content defect, not architectural; but the wrong shape gets baked into stories and test suites for entire ACs, so a late catch is expensive.
Contributor guide
Assessment
This issue has not been assessed yet.