From ab0238e5f72c23999615675a7eb14786e77c5e9d Mon Sep 17 00:00:00 2001 From: Chris George Date: Sun, 13 Sep 2026 23:24:51 +0000 Subject: [PATCH 1/4] chore(contracts): Mirror the cut-kind-census coverage detail code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regenerates the pinned acr contract surface (provisional pin, a lane tip not yet on acr main -- re-pin to the merge sha before this PR merges): a new coverage-detail code, kind_census_truncated, with three additive fields (kind, declared, served). Renders it in CoveragePanel under its own "Kind census" section (kind, "declared N (floor) · served M"), and covers the shape with component tests (present/absent/boundary/no-double-render) and a contract-validation test for the pin. --- scripts/sync-acr-contracts.mjs | 29 +++- src/components/CoveragePanel.test.tsx | 154 +++++++++++++++++- src/components/CoveragePanel.tsx | 58 ++++++- src/contracts/generated/error.ts | 2 +- .../generated/investigation-request.ts | 2 +- .../generated/investigation-result.ts | 8 +- src/contracts/manifest.json | 4 +- .../context_fabric_common.v1.schema.json | 14 +- src/lib/acr/validate.test.ts | 132 +++++++++++++++ 9 files changed, 388 insertions(+), 15 deletions(-) diff --git a/scripts/sync-acr-contracts.mjs b/scripts/sync-acr-contracts.mjs index 4bf3ab0..ece99ec 100644 --- a/scripts/sync-acr-contracts.mjs +++ b/scripts/sync-acr-contracts.mjs @@ -305,7 +305,34 @@ 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 = "9e35fe9405d70879ed41600f3e4f484aea6411b2"; +// 9e35fe94 -> 0b52363b: PROVISIONAL pin, re-pin to the merge sha before this +// PR merges. Verified over the full tree +// (`git diff 9e35fe9405d70879ed41600f3e4f484aea6411b2 +// 0b52363ba45945350e1ff87d6a40d3df2cb42158 -- contracts/`): four files +// change, and two of them are part of this repo's vendored surface. +// - `context_fabric_common.v1`'s `CoverageDetail.code` closed enum gains +// an 18th value, `kind_census_truncated`: a discovered cohort's kind- +// scoped census (the term-free fetch of a declared member kind) was cut +// at its own row bound. Three new additive properties ride with it, +// required together and only for this code: `kind` (the subject kind +// the census was for), `declared` (the census figure observed -- a +// floor) and `served` (how many of that kind made the answer). No +// other property, `$def`, or required-list change in this or the +// answer-projection schema. +// - `context_fabric_answer_projection.v1` carries the identical addition +// (this repo's own vendored copy of the coverage-detail shape). +// - `mcp_investigate_question_response.v1` and +// `mcp_investigation_result_response.v1` also carry the identical +// addition but are not part of this repo's vendored surface -- the +// same exclusion as every bump above. +// `context_fabric_investigation_request.v1`, `error.v1`, and every pinned +// example are byte-identical to the prior pin. +// +// WIDENING ONLY, and load-bearing once acr deploys this sha: the row is +// additive, so every previously-valid response still validates; a response +// carrying the new code is what an un-bumped ask-dev leg would reject as +// acr_contract_violation. +export const SOURCE_COMMIT = "0b52363ba45945350e1ff87d6a40d3df2cb42158"; const PRETTIER_OPTIONS = Object.freeze({ parser: "typescript", diff --git a/src/components/CoveragePanel.test.tsx b/src/components/CoveragePanel.test.tsx index e3e6a8c..14fb085 100644 --- a/src/components/CoveragePanel.test.tsx +++ b/src/components/CoveragePanel.test.tsx @@ -1015,12 +1015,14 @@ describe("CoveragePanel — a detail's code changes nothing about how it renders "requirement_read_not_planned", "read_population_unverified", "fact_read_origin_state", + "kind_census_truncated", ]); }); /** - * Exactly ONE code gets rendering of its own: `fact_read_origin_state`, - * which also produces a per-kind read-state row. Every other code renders + * Exactly TWO codes get rendering of their own: `fact_read_origin_state` + * (a per-kind read-state row) and `kind_census_truncated` (a per-kind + * census row, its own "Kind census" section). Every other code renders * identically for identical text. * * What this pins is the exception SET, so a code quietly GAINING its own @@ -1028,17 +1030,19 @@ describe("CoveragePanel — a detail's code changes nothing about how it renders * own — one with no arm is indistinguishable from one that needs none. The * vocabulary cell above is what stops a new member arriving unnoticed. */ - it("exactly one code renders anything beyond the shared reason rendering", () => { + it("exactly two codes render anything beyond the shared reason rendering", () => { const baseline = renderWithCode("fact_provider_reported"); const different = CODES.filter( (code) => JSON.stringify(renderWithCode(code)) !== JSON.stringify(baseline), ); - expect(different).toEqual(["fact_read_origin_state"]); + expect(different).toEqual(["fact_read_origin_state", "kind_census_truncated"]); }); it("every other code renders identically for identical text", () => { const baseline = renderWithCode("fact_provider_reported"); - for (const code of CODES.filter((c) => c !== "fact_read_origin_state")) { + for (const code of CODES.filter( + (c) => c !== "fact_read_origin_state" && c !== "kind_census_truncated", + )) { expect(renderWithCode(code)).toEqual(baseline); } }); @@ -1059,6 +1063,146 @@ describe("CoveragePanel — a detail's code changes nothing about how it renders }); }); +/** + * kind_census_truncated: a discovered cohort's kind-scoped census was cut, + * with kind/declared/served — additive fields present exactly on this code. + * The whole input domain (present, absent, and the boundary served===declared + * shape) is exercised through the real component render. + */ +describe("CoveragePanel — kind_census_truncated (D47)", () => { + function coverageWithKindCensusDetail( + detail: Partial>, + ) { + return { + sources: [{ source: "context-fabric:graph", state: "available" }], + partial: true, + degraded_reasons: [], + details: [ + { + detail_id: "cov-census-01", + source: "context-fabric:graph", + code: "kind_census_truncated", + degrading: true, + label: "At least 2000 team found; 25 included", + raw: "kind_census_truncated:team:2000:25", + ...detail, + }, + ], + } as unknown as Parameters[0]["coverage"]; + } + + it("shows the kind, the declared/served numbers, and the engine label under its own 'Kind census' heading", () => { + const { container } = render( + , + ); + const panel = container.querySelector('[data-testid="coverage-panel"]')!; + const visible = visibleText(panel); + expect(visible).toContain("Kind census"); + expect(visible).toContain("team"); + expect(visible).toContain("At least 2000 team found; 25 included"); + expect(visible).toContain("declared 2000 (floor) · served 25"); + }); + + it("prefers the synthesis phrasing over the label when both are present, keeping the numbers line separate", () => { + const { container } = render( + , + ); + const visible = visibleText(container.querySelector('[data-testid="coverage-panel"]')!); + expect(visible).toContain("There are far more teams than the census could enumerate."); + expect(visible).toContain("At least 2000 team found; 25 included"); + expect(visible).toContain("declared 2000 (floor) · served 25"); + }); + + it("omits the kind label and the numbers line when kind/declared/served are absent (legacy-shaped detail)", () => { + const { container } = render(); + const visible = visibleText(container.querySelector('[data-testid="coverage-panel"]')!); + expect(visible).toContain("Kind census"); + expect(visible).toContain("At least 2000 team found; 25 included"); + expect(visible).not.toContain("declared"); + expect(visible).not.toContain("served"); + }); + + it("renders the boundary shape served === declared (an uncut census reported some other way) without dividing by anything odd", () => { + const { container } = render( + , + ); + const visible = visibleText(container.querySelector('[data-testid="coverage-panel"]')!); + expect(visible).toContain("declared 5 (floor) · served 5"); + }); + + it("renders served === 0 (no cohort of this kind was assembled) as a real number, not a fallback", () => { + const { container } = render( + , + ); + const visible = visibleText(container.querySelector('[data-testid="coverage-panel"]')!); + expect(visible).toContain("declared 2000 (floor) · served 0"); + }); + + it("does not double-render the row in the generic 'Degraded reasons' list", () => { + const { container } = render( + , + ); + const panel = container.querySelector('[data-testid="coverage-panel"]')!; + expect(panel.textContent ?? "").not.toContain("Degraded reasons"); + }); + + it("still shows a generic degraded reason alongside a kind_census_truncated row, without merging the two", () => { + const coverage = { + sources: [{ source: "context-fabric:graph", state: "available" }], + partial: true, + degraded_reasons: [], + details: [ + { + detail_id: "cov-census-01", + source: "context-fabric:graph", + code: "kind_census_truncated", + degrading: true, + label: "At least 2000 team found; 25 included", + kind: "team", + declared: 2000, + served: 25, + }, + { + detail_id: "cov-fact-01", + source: "canonical_fact:status", + code: "fact_read_failed", + degrading: true, + label: "Status facts could not be read", + }, + ], + } as unknown as Parameters[0]["coverage"]; + const { container } = render(); + const visible = visibleText(container.querySelector('[data-testid="coverage-panel"]')!); + expect(visible).toContain("Kind census"); + expect(visible).toContain("Degraded reasons"); + expect(visible).toContain("At least 2000 team found; 25 included"); + expect(visible).toContain("Status facts could not be read"); + }); +}); + /** * The per-kind read-state rows, against acr's own golden example for the shape. * That document is the case the rows exist for: each row reads `available` while diff --git a/src/components/CoveragePanel.tsx b/src/components/CoveragePanel.tsx index 953403c..65f2e68 100644 --- a/src/components/CoveragePanel.tsx +++ b/src/components/CoveragePanel.tsx @@ -4,6 +4,7 @@ import { Badge } from "@/components/Badge"; import { Details } from "@/components/Details"; import type { Coverage, CoverageDetail } from "@/lib/contracts"; import { + GENERIC_DEGRADED_REASON_SENTENCE, degradedReasonDisplay, degradingDetails as degradingDetailsOf, uncoveredLegacyReasons, @@ -74,6 +75,22 @@ export function CoveragePanel({ coverage }: CoveragePanelProps) { // when byte-identical to a degrading detail's rendered line or its own `raw`. const degradingDetails: readonly CoverageDetail[] = degradingDetailsOf(coverage); const legacyDegradedReasons = uncoveredLegacyReasons(coverage); + // A kind_census_truncated row names WHICH kind's census was cut and BOTH + // numbers: declared (the census figure observed -- a floor) and served + // (how many of that kind made this answer). It is degrading (a real + // coverage loss), so it stays in `degradingDetails` for every consumer + // that counts degradation — but it gets its OWN section here rather than + // the generic "Degraded reasons" list, the same reason `fact_read_origin_state` + // does above: displaying its structured fields (not a derived sentence — + // the numbers are the contract's own `kind`/`declared`/`served`, shown + // verbatim) says more than folding it into one more prose line would. + const kindCensusTruncated = (coverage.details ?? []).filter( + (detail) => detail.code === "kind_census_truncated", + ); + const kindCensusTruncatedIds = new Set(kindCensusTruncated.map((detail) => detail.detail_id)); + const genericDegradingDetails = degradingDetails.filter( + (detail) => !kindCensusTruncatedIds.has(detail.detail_id), + ); // A read-origin-state row reports the state of the population ONE read // actually reached, per origin kind. It is not a degraded reason -- it can // be non-degrading -- and it is not the source fold above it either: a row @@ -244,7 +261,44 @@ export function CoveragePanel({ coverage }: CoveragePanelProps) { )} - {degradingDetails.length === 0 && legacyDegradedReasons.length === 0 ? null : ( + {kindCensusTruncated.length === 0 ? null : ( + <> + {/* Below the per-kind read states, above the generic + degraded-reasons list: a cut kind census is its own + cause, with its own numbers, not a fold over sources. */} +

+ Kind census +

+
    + {kindCensusTruncated.map((detail) => { + const kind = nonBlank(detail.kind); + const phrasing = nonBlank(detail.phrasing); + const facts = nonBlank(detail.label); + return ( +
  • +

    + {kind === undefined ? null : ( + {humanizeTerm(kind)}: + )} + {facts ?? GENERIC_DEGRADED_REASON_SENTENCE} +

    + {phrasing === undefined || phrasing === facts ? null : ( +

    {phrasing}

    + )} + {detail.declared === undefined || + detail.served === undefined ? null : ( +

    + declared {detail.declared} (floor) · served{" "} + {detail.served} +

    + )} +
  • + ); + })} +
+ + )} + {genericDegradingDetails.length === 0 && legacyDegradedReasons.length === 0 ? null : ( <> {/* ONE heading for the union: both lists are the same disclosure, and a response carrying both shapes must not @@ -253,7 +307,7 @@ export function CoveragePanel({ coverage }: CoveragePanelProps) { Degraded reasons
    - {degradingDetails.map((detail) => { + {genericDegradingDetails.map((detail) => { // CHAOS-4690: synthesis-phrased sentence when the // model chose to phrase it, else the deterministic // Label floor; then the raw text, and only then the diff --git a/src/contracts/generated/error.ts b/src/contracts/generated/error.ts index 420e847..e782cf0 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 @ 9e35fe9405d70879ed41600f3e4f484aea6411b2 + * Source: full-chaos/dev-health-acr @ 0b52363ba45945350e1ff87d6a40d3df2cb42158 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-request.ts b/src/contracts/generated/investigation-request.ts index 1ecfc79..f93b0ef 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 @ 9e35fe9405d70879ed41600f3e4f484aea6411b2 + * Source: full-chaos/dev-health-acr @ 0b52363ba45945350e1ff87d6a40d3df2cb42158 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-result.ts b/src/contracts/generated/investigation-result.ts index 0353e57..0b08374 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 @ 9e35fe9405d70879ed41600f3e4f484aea6411b2 + * Source: full-chaos/dev-health-acr @ 0b52363ba45945350e1ff87d6a40d3df2cb42158 * Regenerate with `pnpm acr:contracts:generate --source `. */ @@ -4400,7 +4400,8 @@ export interface CoverageDetail { | "population_truncated" | "requirement_read_not_planned" | "read_population_unverified" - | "fact_read_origin_state"; + | "fact_read_origin_state" + | "kind_census_truncated"; degrading: boolean; fact_kind?: string; source_state?: string; @@ -4421,6 +4422,9 @@ export interface CoverageDetail { label: string; phrasing?: string; raw?: string; + kind?: string; + declared?: number; + served?: number; } export interface VersionSet { service_version: string; diff --git a/src/contracts/manifest.json b/src/contracts/manifest.json index 370bf92..8ef2e46 100644 --- a/src/contracts/manifest.json +++ b/src/contracts/manifest.json @@ -1,5 +1,5 @@ { - "source_commit": "9e35fe9405d70879ed41600f3e4f484aea6411b2", + "source_commit": "0b52363ba45945350e1ff87d6a40d3df2cb42158", "source_repository": "full-chaos/dev-health-acr", "files": [ { @@ -28,7 +28,7 @@ }, { "path": "schemas/context_fabric_common.v1.schema.json", - "sha256": "707acb7ee25e1dbd252847740e3383ec4b204b77e8f0276e33f6911693afcfb8" + "sha256": "6a78e2fc0240001d68c6be8ef6483e81b34ebe458baf49fadd5e844105cbd147" }, { "path": "schemas/context_fabric_investigation_request.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 dcb69fa..85c9fc5 100644 --- a/src/contracts/schemas/context_fabric_common.v1.schema.json +++ b/src/contracts/schemas/context_fabric_common.v1.schema.json @@ -4939,7 +4939,8 @@ "population_truncated", "requirement_read_not_planned", "read_population_unverified", - "fact_read_origin_state" + "fact_read_origin_state", + "kind_census_truncated" ] }, "degrading": { @@ -4996,6 +4997,17 @@ "raw": { "type": "string", "maxLength": 2000 + }, + "kind": { + "type": "string" + }, + "declared": { + "type": "integer", + "minimum": 0 + }, + "served": { + "type": "integer", + "minimum": 0 } }, "required": [ diff --git a/src/lib/acr/validate.test.ts b/src/lib/acr/validate.test.ts index 975acbc..a4f8541 100644 --- a/src/lib/acr/validate.test.ts +++ b/src/lib/acr/validate.test.ts @@ -1737,6 +1737,138 @@ describe("coverage detail contract — the read-origin-state code (consumer pin) }); }); +/** + * `CoverageDetail.code` gains an 18th closed-vocabulary member, + * `kind_census_truncated`: a discovered cohort's kind-scoped census (the + * term-free fetch of a declared member kind) was cut at its own row bound. + * Three additive properties ride with it — `kind`, `declared`, `served` — + * present together on this code and absent on every other. Additive only — + * every document the prior pin accepted still validates, and the vocabulary + * stays closed. + * + * Paired with a reproduction of the PRIOR pin's own schema, so this proves + * the BUMP is what made the value acceptable, not merely that the current + * pin accepts it. + */ +describe("coverage detail contract — the kind_census_truncated code (consumer pin, D47)", () => { + const RESULT = "context_fabric_investigation_result.v1.schema.json"; + + function resultWithDetail(overrides: Record): Record { + const clone = structuredClone(canonicalResult) as unknown as Record; + clone.coverage = { + ...(clone.coverage as Record), + details: [ + { + detail_id: "cov-census-01", + source: "context-fabric:graph", + code: "kind_census_truncated", + degrading: true, + label: "At least 2000 team found; 25 included", + raw: "kind_census_truncated:team:2000:25", + kind: "team", + declared: 2000, + served: 25, + ...overrides, + }, + ], + }; + return clone; + } + + it("GREEN: a degrading detail carrying the new code and all three fields validates at this pin", () => { + const validation = validateContract(RESULT, resultWithDetail({})); + expect(validation.errors).toEqual([]); + expect(validation.valid).toBe(true); + }); + + it("GREEN: the fields are each independently optional at the SCHEMA level (acr's own write path enforces they ride together)", () => { + for (const overrides of [ + { kind: undefined }, + { declared: undefined }, + { served: undefined }, + ]) { + const document = resultWithDetail(overrides); + const details = ( + (document.coverage as Record).details as Array< + Record + > + )[0]!; + for (const [key, value] of Object.entries(overrides)) { + if (value === undefined) delete details[key]; + } + const validation = validateContract(RESULT, document); + expect(validation.errors).toEqual([]); + expect(validation.valid).toBe(true); + } + }); + + it("RED CONTROL: served must be a non-negative integer, not a string or a fraction", () => { + for (const bad of ["25", 2.5, -1]) { + const validation = validateContract(RESULT, resultWithDetail({ served: bad })); + expect(validation.valid).toBe(false); + } + }); + + it("RED CONTROL: declared must be a non-negative integer", () => { + for (const bad of ["2000", -1, 1.1]) { + const validation = validateContract(RESULT, resultWithDetail({ declared: bad })); + expect(validation.valid).toBe(false); + } + }); + + it("the already-live codes still validate", () => { + for (const code of [ + "fact_unconfigured", + "fact_provider_reported", + "fact_read_origin_state", + ]) { + const clone = structuredClone(canonicalResult) as unknown as Record; + clone.coverage = { + ...(clone.coverage as Record), + details: [ + { + detail_id: "cov-x", + source: "canonical_fact:status", + code, + degrading: true, + label: "x", + }, + ], + }; + const validation = validateContract(RESULT, clone); + expect(validation.errors).toEqual([]); + expect(validation.valid).toBe(true); + } + }); + + it("the vocabulary stays CLOSED: a code outside it is still rejected", () => { + const validation = validateContract(RESULT, resultWithDetail({ code: "not_a_real_code" })); + expect(validation.valid).toBe(false); + expect(validation.errors.join("; ")).toMatch(/code must be equal to one of the allowed/); + }); + + it("EXECUTED repro: the prior pin's own schema rejects the new code", () => { + const priorCommon = structuredClone(commonSchema) as unknown as { + $defs: { CoverageDetail: { properties: { code: { enum: string[] } } } }; + }; + const codes = priorCommon.$defs.CoverageDetail.properties.code.enum; + expect(codes).toContain("kind_census_truncated"); + priorCommon.$defs.CoverageDetail.properties.code.enum = codes.filter( + (code) => code !== "kind_census_truncated", + ); + + const ajv = new Ajv2020({ allErrors: true, strictSchema: false, strictTypes: false }); + ajv.addSchema(priorCommon, "context_fabric_common.v1.schema.json"); + const validate = ajv.compile(structuredClone(investigationResultSchema)); + + expect(validate(resultWithDetail({}))).toBe(false); + // The same stand-in still accepts a live code, so it is faithful + // (kind/declared/served ride along as ordinary optional properties + // regardless of code at the SCHEMA level -- see the GREEN test above). + expect(validate(resultWithDetail({ code: "fact_provider_reported" }))).toBe(true); + }); +}); + /** * `ClaimedFact.kind` gains a 23rd member, `cardinality`: the count the service * computes over a resolved member set, minted as a claimed fact whose subject From 23c23becd3100990d53072522e5a6dd1fd4c65b2 Mon Sep 17 00:00:00 2001 From: Chris George Date: Mon, 14 Sep 2026 01:38:08 +0000 Subject: [PATCH 2/4] chore(contracts): Re-pin to the acr fix closing the served-staleness gap Re-pins the provisional acr contract to the tip that derives a cut kind census's served count last, at every serving surface (stage-3 retry and reuse), and closes the kind property to the same closed subject-kind vocabulary Go already enforces. --- scripts/sync-acr-contracts.mjs | 10 +++++++--- src/contracts/generated/error.ts | 2 +- .../generated/investigation-request.ts | 2 +- .../generated/investigation-result.ts | 19 +++++++++++++++++-- src/contracts/manifest.json | 4 ++-- .../context_fabric_common.v1.schema.json | 19 ++++++++++++++++++- 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/scripts/sync-acr-contracts.mjs b/scripts/sync-acr-contracts.mjs index ece99ec..b0be0b5 100644 --- a/scripts/sync-acr-contracts.mjs +++ b/scripts/sync-acr-contracts.mjs @@ -305,10 +305,10 @@ 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. -// 9e35fe94 -> 0b52363b: PROVISIONAL pin, re-pin to the merge sha before this +// 9e35fe94 -> 7ae3719f: PROVISIONAL pin, re-pin to the merge sha before this // PR merges. Verified over the full tree // (`git diff 9e35fe9405d70879ed41600f3e4f484aea6411b2 -// 0b52363ba45945350e1ff87d6a40d3df2cb42158 -- contracts/`): four files +// 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 -- contracts/`): four files // change, and two of them are part of this repo's vendored surface. // - `context_fabric_common.v1`'s `CoverageDetail.code` closed enum gains // an 18th value, `kind_census_truncated`: a discovered cohort's kind- @@ -325,6 +325,10 @@ const ARTIFACT_ROOT = path.join(ROOT, "src/contracts"); // `mcp_investigation_result_response.v1` also carry the identical // addition but are not part of this repo's vendored surface -- the // same exclusion as every bump above. +// - `kind` is closed to the same 15-member subject-kind enum +// `SubjectRef.kind` already publishes (was an unenumerated string in +// the first cut of this pin) -- safe to tighten pre-merge since the +// field carries no production traffic yet. // `context_fabric_investigation_request.v1`, `error.v1`, and every pinned // example are byte-identical to the prior pin. // @@ -332,7 +336,7 @@ const ARTIFACT_ROOT = path.join(ROOT, "src/contracts"); // additive, so every previously-valid response still validates; a response // carrying the new code is what an un-bumped ask-dev leg would reject as // acr_contract_violation. -export const SOURCE_COMMIT = "0b52363ba45945350e1ff87d6a40d3df2cb42158"; +export const SOURCE_COMMIT = "7ae3719fc2b214d60d51cc7d6144dc0a11318f05"; const PRETTIER_OPTIONS = Object.freeze({ parser: "typescript", diff --git a/src/contracts/generated/error.ts b/src/contracts/generated/error.ts index e782cf0..b6b0e6f 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 @ 0b52363ba45945350e1ff87d6a40d3df2cb42158 + * Source: full-chaos/dev-health-acr @ 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-request.ts b/src/contracts/generated/investigation-request.ts index f93b0ef..221ae48 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 @ 0b52363ba45945350e1ff87d6a40d3df2cb42158 + * Source: full-chaos/dev-health-acr @ 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-result.ts b/src/contracts/generated/investigation-result.ts index 0b08374..6a337e4 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 @ 0b52363ba45945350e1ff87d6a40d3df2cb42158 + * Source: full-chaos/dev-health-acr @ 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 * Regenerate with `pnpm acr:contracts:generate --source `. */ @@ -4422,7 +4422,22 @@ export interface CoverageDetail { label: string; phrasing?: string; raw?: string; - kind?: string; + kind?: + | "organization" + | "team" + | "project" + | "repository" + | "work_item" + | "pull_request" + | "deployment" + | "incident" + | "document" + | "decision" + | "episode" + | "metric" + | "pull_request_review" + | "ci_pipeline_run" + | "work_item_ref"; declared?: number; served?: number; } diff --git a/src/contracts/manifest.json b/src/contracts/manifest.json index 8ef2e46..ae9ef98 100644 --- a/src/contracts/manifest.json +++ b/src/contracts/manifest.json @@ -1,5 +1,5 @@ { - "source_commit": "0b52363ba45945350e1ff87d6a40d3df2cb42158", + "source_commit": "7ae3719fc2b214d60d51cc7d6144dc0a11318f05", "source_repository": "full-chaos/dev-health-acr", "files": [ { @@ -28,7 +28,7 @@ }, { "path": "schemas/context_fabric_common.v1.schema.json", - "sha256": "6a78e2fc0240001d68c6be8ef6483e81b34ebe458baf49fadd5e844105cbd147" + "sha256": "574d09fc77d4ad28641e2d7beafe6125a18738929baadb9b9be8c78dbfda8494" }, { "path": "schemas/context_fabric_investigation_request.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 85c9fc5..ff7fa93 100644 --- a/src/contracts/schemas/context_fabric_common.v1.schema.json +++ b/src/contracts/schemas/context_fabric_common.v1.schema.json @@ -4999,7 +4999,24 @@ "maxLength": 2000 }, "kind": { - "type": "string" + "type": "string", + "enum": [ + "organization", + "team", + "project", + "repository", + "work_item", + "pull_request", + "deployment", + "incident", + "document", + "decision", + "episode", + "metric", + "pull_request_review", + "ci_pipeline_run", + "work_item_ref" + ] }, "declared": { "type": "integer", From a92d7784599ab8e926cfabf110823e014c4dd054 Mon Sep 17 00:00:00 2001 From: Chris George Date: Mon, 14 Sep 2026 01:58:57 +0000 Subject: [PATCH 3/4] chore(contracts): Re-pin to the comment-only acr follow-up Re-pins the provisional acr contract to its next tip; contracts/ and internal/mcp/schemas/ are byte-identical to the prior pin (acr's change there was comment-only), so only the source-commit pointer and generated-file banners move. --- scripts/sync-acr-contracts.mjs | 7 ++++++- src/contracts/generated/error.ts | 2 +- src/contracts/generated/investigation-request.ts | 2 +- src/contracts/generated/investigation-result.ts | 2 +- src/contracts/manifest.json | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/scripts/sync-acr-contracts.mjs b/scripts/sync-acr-contracts.mjs index b0be0b5..fd70448 100644 --- a/scripts/sync-acr-contracts.mjs +++ b/scripts/sync-acr-contracts.mjs @@ -336,7 +336,12 @@ const ARTIFACT_ROOT = path.join(ROOT, "src/contracts"); // additive, so every previously-valid response still validates; a response // carrying the new code is what an un-bumped ask-dev leg would reject as // acr_contract_violation. -export const SOURCE_COMMIT = "7ae3719fc2b214d60d51cc7d6144dc0a11318f05"; +// 7ae3719f -> 72c9e3ea: PROVISIONAL pin, re-pin to the merge sha before this +// PR merges. `git diff 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 +// 72c9e3ea21b2e10e1537c502bd13d2be5e446664 -- contracts/ internal/mcp/schemas/` +// is empty: no schema, example, or manifest content changed. Every vendored +// file stays byte-identical to the prior pin; only this pointer moves. +export const SOURCE_COMMIT = "72c9e3ea21b2e10e1537c502bd13d2be5e446664"; const PRETTIER_OPTIONS = Object.freeze({ parser: "typescript", diff --git a/src/contracts/generated/error.ts b/src/contracts/generated/error.ts index b6b0e6f..d6443cc 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 @ 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 + * Source: full-chaos/dev-health-acr @ 72c9e3ea21b2e10e1537c502bd13d2be5e446664 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-request.ts b/src/contracts/generated/investigation-request.ts index 221ae48..c2a268a 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 @ 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 + * Source: full-chaos/dev-health-acr @ 72c9e3ea21b2e10e1537c502bd13d2be5e446664 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-result.ts b/src/contracts/generated/investigation-result.ts index 6a337e4..9dbe41f 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 @ 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 + * Source: full-chaos/dev-health-acr @ 72c9e3ea21b2e10e1537c502bd13d2be5e446664 * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/manifest.json b/src/contracts/manifest.json index ae9ef98..58c35a2 100644 --- a/src/contracts/manifest.json +++ b/src/contracts/manifest.json @@ -1,5 +1,5 @@ { - "source_commit": "7ae3719fc2b214d60d51cc7d6144dc0a11318f05", + "source_commit": "72c9e3ea21b2e10e1537c502bd13d2be5e446664", "source_repository": "full-chaos/dev-health-acr", "files": [ { From 4521536952e90be5f39e83c618dd32bfbc8acfca Mon Sep 17 00:00:00 2001 From: Chris George Date: Mon, 14 Sep 2026 02:56:05 +0000 Subject: [PATCH 4/4] chore(contracts): Re-pin to the merged acr tip Re-pins to acr main's squash of the kind-census coverage detail work; every vendored file stays byte-identical to the pre-merge pin, only the source-commit pointer and generated-file banners move. --- scripts/sync-acr-contracts.mjs | 8 +++++--- src/contracts/generated/error.ts | 2 +- src/contracts/generated/investigation-request.ts | 2 +- src/contracts/generated/investigation-result.ts | 2 +- src/contracts/manifest.json | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/sync-acr-contracts.mjs b/scripts/sync-acr-contracts.mjs index fd70448..e1d8217 100644 --- a/scripts/sync-acr-contracts.mjs +++ b/scripts/sync-acr-contracts.mjs @@ -336,12 +336,14 @@ const ARTIFACT_ROOT = path.join(ROOT, "src/contracts"); // additive, so every previously-valid response still validates; a response // carrying the new code is what an un-bumped ask-dev leg would reject as // acr_contract_violation. -// 7ae3719f -> 72c9e3ea: PROVISIONAL pin, re-pin to the merge sha before this -// PR merges. `git diff 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 +// 7ae3719f -> 72c9e3ea: `git diff 7ae3719fc2b214d60d51cc7d6144dc0a11318f05 // 72c9e3ea21b2e10e1537c502bd13d2be5e446664 -- contracts/ internal/mcp/schemas/` // is empty: no schema, example, or manifest content changed. Every vendored // file stays byte-identical to the prior pin; only this pointer moves. -export const SOURCE_COMMIT = "72c9e3ea21b2e10e1537c502bd13d2be5e446664"; +// 72c9e3ea -> a57b599b: the acr PR merged (squash). Final pin -- every +// vendored file byte-identical to the pre-merge pin (squash preserves the +// tree; verified per-file blob shas against the merged sha on acr main). +export const SOURCE_COMMIT = "a57b599b88a28c170444e786d701af980911db9d"; const PRETTIER_OPTIONS = Object.freeze({ parser: "typescript", diff --git a/src/contracts/generated/error.ts b/src/contracts/generated/error.ts index d6443cc..def48e5 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 @ 72c9e3ea21b2e10e1537c502bd13d2be5e446664 + * Source: full-chaos/dev-health-acr @ a57b599b88a28c170444e786d701af980911db9d * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-request.ts b/src/contracts/generated/investigation-request.ts index c2a268a..5bea81e 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 @ 72c9e3ea21b2e10e1537c502bd13d2be5e446664 + * Source: full-chaos/dev-health-acr @ a57b599b88a28c170444e786d701af980911db9d * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/generated/investigation-result.ts b/src/contracts/generated/investigation-result.ts index 9dbe41f..f655269 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 @ 72c9e3ea21b2e10e1537c502bd13d2be5e446664 + * Source: full-chaos/dev-health-acr @ a57b599b88a28c170444e786d701af980911db9d * Regenerate with `pnpm acr:contracts:generate --source `. */ diff --git a/src/contracts/manifest.json b/src/contracts/manifest.json index 58c35a2..610eebf 100644 --- a/src/contracts/manifest.json +++ b/src/contracts/manifest.json @@ -1,5 +1,5 @@ { - "source_commit": "72c9e3ea21b2e10e1537c502bd13d2be5e446664", + "source_commit": "a57b599b88a28c170444e786d701af980911db9d", "source_repository": "full-chaos/dev-health-acr", "files": [ {