diff --git a/scripts/sync-acr-contracts.mjs b/scripts/sync-acr-contracts.mjs
index b500df2..15d3bfc 100644
--- a/scripts/sync-acr-contracts.mjs
+++ b/scripts/sync-acr-contracts.mjs
@@ -305,7 +305,7 @@ const ARTIFACT_ROOT = path.join(ROOT, "src/contracts");
// WIDENING ONLY, and load-bearing: acr main mints this claim, so without the
// bump a response carrying it is rejected whole as `acr_contract_violation`
// instead of rendering.
-export const SOURCE_COMMIT = "fe3fe467afb91323eaa8d122be7f78a5e6758e3b";
+export const SOURCE_COMMIT = "74d8fc4c32a288fcb5b20fbeac335e17cf642be9";
const PRETTIER_OPTIONS = Object.freeze({
parser: "typescript",
diff --git a/src/components/DeterministicAnswerView.test.tsx b/src/components/DeterministicAnswerView.test.tsx
index ae3340d..136aa95 100644
--- a/src/components/DeterministicAnswerView.test.tsx
+++ b/src/components/DeterministicAnswerView.test.tsx
@@ -382,3 +382,36 @@ describe("DeterministicAnswerView: a refused continuation still shows the servic
expect(withText).toBe(withoutText);
});
});
+
+/**
+ * The user-facing wording of the organization-scope refusal is the service's
+ * own fixed sentence (ACR `ContextFabricOrganizationScopeUnsupportedLimitation`):
+ * it says organization-wide analysis of status, health or drivers is not
+ * supported, and that organization-wide counts are. The view renders it as
+ * visible text under Limitations; the basis itself is a machine field the view
+ * does not key off.
+ */
+describe("DeterministicAnswerView: an organization-scope refusal shows what is and is not supported", () => {
+ const SENTENCE =
+ "This question was read as being about the organization as a whole. Organization-wide analysis of status, health or drivers is not supported; organization-wide counts of one kind of subject, such as how many repositories or teams there are, are supported. No canonical facts were read.";
+
+ function refusedOrganizationQuestion(): InvestigationResult {
+ const base = mockScenarios().find((s) => s.id === "complete")!.result;
+ return {
+ ...structuredClone(base),
+ status: "no_match",
+ refusal_basis: "organization_scope_unsupported",
+ limitations: [SENTENCE],
+ } as unknown as InvestigationResult;
+ }
+
+ it("renders the sentence as visible text, including what IS supported", () => {
+ render();
+ const article = screen.getByRole("article", { name: "Deterministic answer" });
+ const text = visibleText(article);
+ expect(text).toContain(SENTENCE);
+ expect(text).toContain("organization-wide counts");
+ expect(text).not.toContain("The server refused this question on the basis");
+ expect(screen.getByRole("heading", { name: "Limitations" })).toBeInTheDocument();
+ });
+});
diff --git a/src/contracts/generated/error.ts b/src/contracts/generated/error.ts
index 3fb0569..9ba8348 100644
--- a/src/contracts/generated/error.ts
+++ b/src/contracts/generated/error.ts
@@ -1,7 +1,7 @@
/* eslint-disable */
/**
* GENERATED by scripts/sync-acr-contracts.mjs. DO NOT EDIT.
- * Source: full-chaos/dev-health-acr @ fe3fe467afb91323eaa8d122be7f78a5e6758e3b
+ * Source: full-chaos/dev-health-acr @ 74d8fc4c32a288fcb5b20fbeac335e17cf642be9
* Regenerate with `pnpm acr:contracts:generate --source `.
*/
diff --git a/src/contracts/generated/investigation-request.ts b/src/contracts/generated/investigation-request.ts
index c17dbe2..9ebb4f0 100644
--- a/src/contracts/generated/investigation-request.ts
+++ b/src/contracts/generated/investigation-request.ts
@@ -1,7 +1,7 @@
/* eslint-disable */
/**
* GENERATED by scripts/sync-acr-contracts.mjs. DO NOT EDIT.
- * Source: full-chaos/dev-health-acr @ fe3fe467afb91323eaa8d122be7f78a5e6758e3b
+ * Source: full-chaos/dev-health-acr @ 74d8fc4c32a288fcb5b20fbeac335e17cf642be9
* Regenerate with `pnpm acr:contracts:generate --source `.
*/
diff --git a/src/contracts/generated/investigation-result.ts b/src/contracts/generated/investigation-result.ts
index 4c022eb..e5ae491 100644
--- a/src/contracts/generated/investigation-result.ts
+++ b/src/contracts/generated/investigation-result.ts
@@ -1,7 +1,7 @@
/* eslint-disable */
/**
* GENERATED by scripts/sync-acr-contracts.mjs. DO NOT EDIT.
- * Source: full-chaos/dev-health-acr @ fe3fe467afb91323eaa8d122be7f78a5e6758e3b
+ * Source: full-chaos/dev-health-acr @ 74d8fc4c32a288fcb5b20fbeac335e17cf642be9
* Regenerate with `pnpm acr:contracts:generate --source `.
*/
@@ -146,7 +146,8 @@ export type ACRContextFabricInvestigationResultV1 = {
| "frame_invariant_violated"
| "unspecified"
| "continuation_context_unverifiable"
- | "declared_kind_unmatched";
+ | "declared_kind_unmatched"
+ | "organization_scope_unsupported";
};
export type InterpretedQuestion = {
[k: string]: unknown | undefined;
@@ -2839,7 +2840,8 @@ export type AnswerCompleteness = {
| "frame_invariant_violated"
| "unspecified"
| "continuation_context_unverifiable"
- | "declared_kind_unmatched";
+ | "declared_kind_unmatched"
+ | "organization_scope_unsupported";
};
export interface FactRequirement {
diff --git a/src/contracts/manifest.json b/src/contracts/manifest.json
index b123856..3b71d5c 100644
--- a/src/contracts/manifest.json
+++ b/src/contracts/manifest.json
@@ -1,5 +1,5 @@
{
- "source_commit": "fe3fe467afb91323eaa8d122be7f78a5e6758e3b",
+ "source_commit": "74d8fc4c32a288fcb5b20fbeac335e17cf642be9",
"source_repository": "full-chaos/dev-health-acr",
"files": [
{
@@ -28,7 +28,7 @@
},
{
"path": "schemas/context_fabric_common.v1.schema.json",
- "sha256": "695065e0da7c731d1ee2d8efcc3fed9a7c6b4a95c58b99d1c76025185706e803"
+ "sha256": "707acb7ee25e1dbd252847740e3383ec4b204b77e8f0276e33f6911693afcfb8"
},
{
"path": "schemas/context_fabric_investigation_request.v1.schema.json",
@@ -36,7 +36,7 @@
},
{
"path": "schemas/context_fabric_investigation_result.v1.schema.json",
- "sha256": "e8ef8ce7a446e17684371ad0279de20783a0e207877d763d8557f20f1a57843f"
+ "sha256": "47d6dd017133b29db1d11775d99b8e6d08614c7d759c112f5899eb1a63b65c86"
},
{
"path": "schemas/error.v1.schema.json",
diff --git a/src/contracts/schemas/context_fabric_common.v1.schema.json b/src/contracts/schemas/context_fabric_common.v1.schema.json
index 0ee96e3..dcb69fa 100644
--- a/src/contracts/schemas/context_fabric_common.v1.schema.json
+++ b/src/contracts/schemas/context_fabric_common.v1.schema.json
@@ -3268,7 +3268,8 @@
"frame_invariant_violated",
"unspecified",
"continuation_context_unverifiable",
- "declared_kind_unmatched"
+ "declared_kind_unmatched",
+ "organization_scope_unsupported"
],
"description": "CHAOS-5442: names WHY the server refused to act on this question's frame, over a closed vocabulary. ABSENT on every turn that was not refused -- absence means \"not refused\", never \"refused for a reason nobody recorded\" (that state is the `unspecified` member). Orthogonal to terminal_reason, which names the CHANNEL an explanation travelled through rather than the decision taken: a refused frame carries both. `continuation_context_unverifiable` refuses a window-only continuation whose prior semantic context the server could not verify; it is not a frame refusal, and the document carries its own fixed limitation sentence."
}
diff --git a/src/contracts/schemas/context_fabric_investigation_result.v1.schema.json b/src/contracts/schemas/context_fabric_investigation_result.v1.schema.json
index ef6642f..6190435 100644
--- a/src/contracts/schemas/context_fabric_investigation_result.v1.schema.json
+++ b/src/contracts/schemas/context_fabric_investigation_result.v1.schema.json
@@ -219,7 +219,8 @@
"frame_invariant_violated",
"unspecified",
"continuation_context_unverifiable",
- "declared_kind_unmatched"
+ "declared_kind_unmatched",
+ "organization_scope_unsupported"
],
"description": "CHAOS-5442: names WHY the server refused to act on this question's frame, over a closed vocabulary. ABSENT on every turn that was not refused -- absence means \"not refused\", never \"refused for a reason nobody recorded\" (that state is the `unspecified` member). Orthogonal to terminal_reason, which names the CHANNEL an explanation travelled through rather than the decision taken: a refused frame carries both. `continuation_context_unverifiable` refuses a window-only continuation whose prior semantic context the server could not verify; it is not a frame refusal, and the document carries its own fixed limitation sentence."
}
diff --git a/src/lib/acr/validate.test.ts b/src/lib/acr/validate.test.ts
index 5274469..09c6ec8 100644
--- a/src/lib/acr/validate.test.ts
+++ b/src/lib/acr/validate.test.ts
@@ -1346,8 +1346,8 @@ describe("investigation result contract — the continuation-refusal basis (cons
).$defs.AnswerCompleteness.properties.refusal_basis.enum;
expect(resultEnum).toContain("continuation_context_unverifiable");
expect(commonEnum).toContain("continuation_context_unverifiable");
- expect(resultEnum).toHaveLength(5);
- expect(commonEnum).toHaveLength(5);
+ expect(resultEnum).toHaveLength(6);
+ expect(commonEnum).toHaveLength(6);
expect([...resultEnum].sort()).toEqual([...commonEnum].sort());
});
@@ -1494,6 +1494,106 @@ describe("investigation result contract — the declared-kind terminal basis (co
});
});
+/**
+ * `refusal_basis` gains a 6th member, `organization_scope_unsupported`: the
+ * question made the organization itself the subject and asked for something
+ * other than a count -- its state, health or drivers -- which is not a
+ * capability the service has. Organization-wide counts of one kind of subject
+ * are supported, and the document's own fixed sentence says so.
+ *
+ * It is NOT `declared_kind_unmatched`, which refuses a question because none of
+ * the options found could be chosen to answer it: for an organization-wide
+ * health question no option could ever be the answer, because its subject is
+ * the organization itself.
+ * It is not a frame refusal either. The field is carried at the same two places
+ * as every other member, and the prior pin rejects the value, so the bump is
+ * what turns this truthful refusal into an answer this workbench can render.
+ */
+describe("investigation result contract — the organization-scope refusal basis (consumer pin)", () => {
+ const RESULT = "context_fabric_investigation_result.v1.schema.json";
+ const MEMBER = "organization_scope_unsupported";
+
+ function withRefusalBasis(value: string): Record {
+ return { ...structuredClone(canonicalResult), refusal_basis: value };
+ }
+
+ it("GREEN: organization_scope_unsupported validates at this pin", () => {
+ const validation = validateContract(RESULT, withRefusalBasis(MEMBER));
+ expect(validation.errors).toEqual([]);
+ expect(validation.valid).toBe(true);
+ });
+
+ it("every earlier member still validates alongside it", () => {
+ for (const value of [
+ "member_kind_unservable",
+ "frame_invariant_violated",
+ "unspecified",
+ "continuation_context_unverifiable",
+ "declared_kind_unmatched",
+ ]) {
+ const validation = validateContract(RESULT, withRefusalBasis(value));
+ expect(validation.errors).toEqual([]);
+ expect(validation.valid).toBe(true);
+ }
+ });
+
+ it("the vocabulary stays CLOSED around the new member: near-misses are rejected", () => {
+ for (const value of [
+ "organization_scope_unsupported_",
+ "ORGANIZATION_SCOPE_UNSUPPORTED",
+ "organization_scope",
+ ]) {
+ expect(validateContract(RESULT, withRefusalBasis(value)).valid).toBe(false);
+ }
+ });
+
+ it("both vocabularies carry the member — as enum values, not as description text", () => {
+ const resultEnum = (
+ investigationResultSchema as unknown as {
+ properties: { refusal_basis: { enum: string[] } };
+ }
+ ).properties.refusal_basis.enum;
+ const commonEnum = (
+ commonSchema as unknown as {
+ $defs: {
+ AnswerCompleteness: { properties: { refusal_basis: { enum: string[] } } };
+ };
+ }
+ ).$defs.AnswerCompleteness.properties.refusal_basis.enum;
+ expect(resultEnum).toContain(MEMBER);
+ expect(commonEnum).toContain(MEMBER);
+ expect([...resultEnum].sort()).toEqual([...commonEnum].sort());
+ });
+
+ it("BEHAVIOURAL: the new value validates at completeness.refusal_basis too", () => {
+ const doc = structuredClone(canonicalResult) as unknown as Record;
+ doc.completeness = {
+ ...(doc.completeness as Record),
+ refusal_basis: MEMBER,
+ };
+ const validation = validateContract(RESULT, doc);
+ expect(validation.errors).toEqual([]);
+ expect(validation.valid).toBe(true);
+ });
+
+ it("EXECUTED repro: the prior pin's own schema rejects the new value", () => {
+ const priorResult = structuredClone(investigationResultSchema) as unknown as {
+ properties: { refusal_basis: { enum: string[] } };
+ };
+ expect(priorResult.properties.refusal_basis.enum).toContain(MEMBER);
+ priorResult.properties.refusal_basis.enum =
+ priorResult.properties.refusal_basis.enum.filter((value) => value !== MEMBER);
+
+ const ajv = new Ajv2020({ allErrors: true, strictSchema: false, strictTypes: false });
+ ajv.addSchema(commonSchema, "context_fabric_common.v1.schema.json");
+ const validate = ajv.compile(priorResult);
+
+ expect(validate(withRefusalBasis(MEMBER))).toBe(false);
+ // The stand-in still accepts the previous member, so it is faithful.
+ expect(validate(withRefusalBasis("declared_kind_unmatched"))).toBe(true);
+ });
+});
+
/**
* `CoverageDetail.code` gains a 17th closed-vocabulary member,
* `fact_read_origin_state`: the code the service publishes when a requirement's