archctx 0.9.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/archctx.mjs CHANGED
@@ -1961,6 +1961,450 @@ var init_projection = __esm(() => {
1961
1961
  ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/;
1962
1962
  });
1963
1963
 
1964
+ // packages/contracts/src/projection-manifest.ts
1965
+ function isRuntimeTopologyTargetType(type) {
1966
+ return typeof type === "string" && RUNTIME_TOPOLOGY_TARGET_TYPES.includes(type);
1967
+ }
1968
+ function architectureDocsProjectionManifestIssues(value) {
1969
+ const issues = [];
1970
+ const manifest = record2(value);
1971
+ if (!manifest)
1972
+ return ["manifest must be an object"];
1973
+ issues.push(...exactKeys(manifest, ["schemaVersion", "rendererVersion", "profile", "layoutVersion", "generatedFrom", "semanticBaseline", "targets"], ["minimumRendererVersion", "minimumProtocolVersion"], "manifest"));
1974
+ if (manifest.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION)
1975
+ issues.push("manifest.schemaVersion is unsupported");
1976
+ if (!isNonEmptyString(manifest.rendererVersion))
1977
+ issues.push("manifest.rendererVersion must be a non-empty string");
1978
+ for (const [key, family] of [["minimumRendererVersion", "archcontext.docs-renderer/v"], ["minimumProtocolVersion", "archcontext.projection-request/v"]]) {
1979
+ if (Object.hasOwn(manifest, key) && versionNumber(manifest[key], family) === undefined)
1980
+ issues.push(`manifest.${key} must name a supported version family`);
1981
+ }
1982
+ if (!ARCHITECTURE_DOCS_PROJECTION_PROFILES.includes(manifest.profile))
1983
+ issues.push("manifest.profile is unsupported");
1984
+ if (manifest.layoutVersion !== ARCHITECTURE_DOCS_LAYOUT_VERSION_V1)
1985
+ issues.push("manifest.layoutVersion is unsupported");
1986
+ issues.push(...generatedFromIssues(manifest.generatedFrom, "manifest.generatedFrom"));
1987
+ const baseline = record2(manifest.semanticBaseline);
1988
+ if (!baseline)
1989
+ issues.push("manifest.semanticBaseline must be an object");
1990
+ else {
1991
+ issues.push(...exactKeys(baseline, ["modelDigest", "capabilities"], [], "manifest.semanticBaseline"));
1992
+ if (!isDigest(baseline.modelDigest))
1993
+ issues.push("manifest.semanticBaseline.modelDigest must be a SHA-256 digest");
1994
+ issues.push(...capabilityEntriesIssues(baseline.capabilities, "manifest.semanticBaseline.capabilities", true));
1995
+ }
1996
+ const targets = record2(manifest.targets);
1997
+ if (!targets) {
1998
+ issues.push("manifest.targets must be an object keyed by targetId");
1999
+ return issues;
2000
+ }
2001
+ const paths = new Set;
2002
+ const stampOwners = new Map;
2003
+ let topologyStamps;
2004
+ for (const [targetId, row] of Object.entries(targets)) {
2005
+ const prefix = `manifest.targets[${JSON.stringify(targetId)}]`;
2006
+ if (!isNonEmptyString(targetId))
2007
+ issues.push("manifest.targets keys must be non-empty targetIds");
2008
+ issues.push(...manifestTargetIssues(row, prefix));
2009
+ const path = record2(row)?.path;
2010
+ if (typeof path === "string") {
2011
+ if (paths.has(path))
2012
+ issues.push(`${prefix}.path is recorded by another target`);
2013
+ paths.add(path);
2014
+ }
2015
+ const stamps = record2(record2(row)?.sourceStamps) ?? {};
2016
+ if (isRuntimeTopologyTargetType(record2(row)?.type)) {
2017
+ const serialized = JSON.stringify(Object.keys(stamps).sort(compareStrings).map((nodeId) => [nodeId, stamps[nodeId]]));
2018
+ if (topologyStamps === undefined)
2019
+ topologyStamps = { targetId, stamps: serialized };
2020
+ else if (topologyStamps.stamps !== serialized)
2021
+ issues.push(`${prefix}.sourceStamps must equal the sourceStamps of ${topologyStamps.targetId}`);
2022
+ for (const nodeId of Object.keys(stamps)) {
2023
+ const owner = stampOwners.get(nodeId);
2024
+ if (owner !== undefined && !isRuntimeTopologyTargetType(record2(targets[owner])?.type))
2025
+ issues.push(`${prefix}.sourceStamps.${nodeId} is already stamped on ${owner}`);
2026
+ else if (owner === undefined)
2027
+ stampOwners.set(nodeId, targetId);
2028
+ }
2029
+ continue;
2030
+ }
2031
+ for (const nodeId of Object.keys(stamps)) {
2032
+ const owner = stampOwners.get(nodeId);
2033
+ if (owner !== undefined)
2034
+ issues.push(`${prefix}.sourceStamps.${nodeId} is already stamped on ${owner}`);
2035
+ else
2036
+ stampOwners.set(nodeId, targetId);
2037
+ }
2038
+ }
2039
+ return issues;
2040
+ }
2041
+ function architectureDocsProjectionManifestSchemaVersion(body) {
2042
+ let parsed;
2043
+ try {
2044
+ parsed = JSON.parse(body);
2045
+ } catch {
2046
+ return;
2047
+ }
2048
+ const schemaVersion = record2(parsed)?.schemaVersion;
2049
+ return typeof schemaVersion === "string" ? schemaVersion : undefined;
2050
+ }
2051
+ function isSupersededArchitectureDocsProjectionManifestSchemaVersion(schemaVersion) {
2052
+ return SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS.includes(schemaVersion);
2053
+ }
2054
+ function serializeArchitectureDocsProjectionManifest(manifest) {
2055
+ const capabilities = [...manifest.semanticBaseline.capabilities].sort((left, right) => compareStrings(left.capabilityId, right.capabilityId)).map(canonicalCapability);
2056
+ const capabilityBlock = JSON.stringify(capabilities, null, 2).split(`
2057
+ `).map((line, index) => index === 0 ? line : ` ${line}`).join(`
2058
+ `);
2059
+ const targetIds = Object.keys(manifest.targets).sort(compareStrings);
2060
+ const targetLines = targetIds.length === 0 ? [' "targets": {}'] : [
2061
+ ' "targets": {',
2062
+ ...targetIds.flatMap((targetId, index) => [
2063
+ ` ${JSON.stringify(targetId)}:`,
2064
+ ` ${JSON.stringify(canonicalTargetRow(manifest.targets[targetId]))}${index === targetIds.length - 1 ? "" : ","}`
2065
+ ]),
2066
+ " }"
2067
+ ];
2068
+ return [
2069
+ "{",
2070
+ ` "schemaVersion": ${JSON.stringify(manifest.schemaVersion)},`,
2071
+ ` "rendererVersion": ${JSON.stringify(manifest.rendererVersion)},`,
2072
+ ...manifest.minimumRendererVersion === undefined ? [] : [` "minimumRendererVersion": ${JSON.stringify(manifest.minimumRendererVersion)},`],
2073
+ ...manifest.minimumProtocolVersion === undefined ? [] : [` "minimumProtocolVersion": ${JSON.stringify(manifest.minimumProtocolVersion)},`],
2074
+ ` "profile": ${JSON.stringify(manifest.profile)},`,
2075
+ ` "layoutVersion": ${JSON.stringify(manifest.layoutVersion)},`,
2076
+ ` "generatedFrom": ${JSON.stringify({ codeGraphPackage: manifest.generatedFrom.codeGraphPackage, codeGraphVersion: manifest.generatedFrom.codeGraphVersion })},`,
2077
+ ' "semanticBaseline": {',
2078
+ ` "modelDigest": ${JSON.stringify(manifest.semanticBaseline.modelDigest)},`,
2079
+ ` "capabilities": ${capabilityBlock}`,
2080
+ " },",
2081
+ ...targetLines,
2082
+ "}",
2083
+ ""
2084
+ ].join(`
2085
+ `);
2086
+ }
2087
+ function architectureDocsProjectionManifestSemanticState(manifest) {
2088
+ return architectureSemanticStateFromCapabilities(manifest.semanticBaseline.capabilities.map(({ selectorEvidenceDigest: _selectorEvidenceDigest, ...capability }) => capability));
2089
+ }
2090
+ function architectureSemanticStateFromCapabilities(capabilities) {
2091
+ const sorted = [...capabilities].sort((left, right) => compareStrings(left.capabilityId, right.capabilityId));
2092
+ return {
2093
+ schemaVersion: ARCHITECTURE_SEMANTIC_STATE_SCHEMA_VERSION,
2094
+ capabilities: sorted,
2095
+ semanticFingerprint: digestJson(sorted.map(({ capabilityId, semanticFingerprint }) => ({ capabilityId, semanticFingerprint }))),
2096
+ flowProofFingerprint: digestJson(sorted.map(({ capabilityId, flowProofFingerprint }) => ({ capabilityId, flowProofFingerprint })))
2097
+ };
2098
+ }
2099
+ function architectureDocsProjectionManifestSourceStamps(manifest) {
2100
+ const stamps = {};
2101
+ for (const row of Object.values(manifest.targets))
2102
+ Object.assign(stamps, row.sourceStamps ?? {});
2103
+ return stamps;
2104
+ }
2105
+ function architectureDocsProjectionManifestProofEvidence(manifest) {
2106
+ return {
2107
+ rendererVersion: manifest.rendererVersion,
2108
+ selectorEvidenceDigests: Object.fromEntries(manifest.semanticBaseline.capabilities.map((capability) => [capability.capabilityId, capability.selectorEvidenceDigest])),
2109
+ sourceStamps: architectureDocsProjectionManifestSourceStamps(manifest)
2110
+ };
2111
+ }
2112
+ function architectureSourceStampsDigest(stamps) {
2113
+ return digestJson({
2114
+ schemaVersion: "archcontext.architecture-source-stamps/v1",
2115
+ stamps: Object.keys(stamps).sort(compareStrings).map((nodeId) => ({ nodeId, digest: stamps[nodeId] }))
2116
+ });
2117
+ }
2118
+ function architectureProjectionOutputsDigest(input) {
2119
+ return digestJson({
2120
+ schemaVersion: "archcontext.architecture-projection-outputs/v1",
2121
+ rendererVersion: input.rendererVersion,
2122
+ profile: input.profile,
2123
+ outputs: Object.keys(input.outputDigests).sort(compareStrings).map((targetId) => ({ targetId, outputDigest: input.outputDigests[targetId] }))
2124
+ });
2125
+ }
2126
+ function architectureDocsProjectionManifestDigests(manifest) {
2127
+ return {
2128
+ modelDigest: manifest.semanticBaseline.modelDigest,
2129
+ sourceTreeDigest: architectureSourceStampsDigest(architectureDocsProjectionManifestSourceStamps(manifest)),
2130
+ flowProofDigest: architectureDocsProjectionManifestSemanticState(manifest).flowProofFingerprint,
2131
+ projectionDigest: architectureProjectionOutputsDigest({
2132
+ rendererVersion: manifest.rendererVersion,
2133
+ profile: manifest.profile,
2134
+ outputDigests: Object.fromEntries(Object.entries(manifest.targets).map(([targetId, row]) => [targetId, row.outputDigest]))
2135
+ })
2136
+ };
2137
+ }
2138
+ function architectureDocsProjectionProvenanceIssues(value, prefix = "provenance") {
2139
+ const provenance = record2(value);
2140
+ if (!provenance)
2141
+ return [`${prefix} must be an object`];
2142
+ const issues = exactKeys(provenance, ["schemaVersion", "sourceTreeDigest", "modelDigest", "projectionInputDigest", "rendererVersion", "layoutVersion", "generatedFrom"], [], prefix);
2143
+ if (provenance.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_PROVENANCE_SCHEMA_VERSION)
2144
+ issues.push(`${prefix}.schemaVersion is unsupported`);
2145
+ for (const field of ["sourceTreeDigest", "modelDigest", "projectionInputDigest"]) {
2146
+ if (!isDigest(provenance[field]))
2147
+ issues.push(`${prefix}.${field} must be a SHA-256 digest`);
2148
+ }
2149
+ if (provenance.rendererVersion !== ARCHITECTURE_DOCS_RENDERER_VERSION)
2150
+ issues.push(`${prefix}.rendererVersion must be ${ARCHITECTURE_DOCS_RENDERER_VERSION}`);
2151
+ if (provenance.layoutVersion !== ARCHITECTURE_DOCS_LAYOUT_VERSION_V1)
2152
+ issues.push(`${prefix}.layoutVersion is unsupported`);
2153
+ issues.push(...generatedFromIssues(provenance.generatedFrom, `${prefix}.generatedFrom`));
2154
+ return issues;
2155
+ }
2156
+ function capabilityEntriesIssues(value, prefix, withSelectorEvidence) {
2157
+ if (!Array.isArray(value))
2158
+ return [`${prefix} must be an array`];
2159
+ const issues = [];
2160
+ const ids = value.map((entry) => record2(entry)?.capabilityId);
2161
+ if (!isSortedUniqueStrings(ids))
2162
+ issues.push(`${prefix} must be sorted and unique by capabilityId`);
2163
+ value.forEach((entry, index) => {
2164
+ const entryPrefix = `${prefix}[${index}]`;
2165
+ const capability = record2(entry);
2166
+ if (!capability) {
2167
+ issues.push(`${entryPrefix} must be an object`);
2168
+ return;
2169
+ }
2170
+ const required = ["capabilityId", "memberNodeIds", "semanticFingerprint", "flowProofFingerprint", "proofStatus", "facets", ...withSelectorEvidence ? ["selectorEvidenceDigest"] : []];
2171
+ issues.push(...exactKeys(capability, required, [], entryPrefix));
2172
+ if (!isNonEmptyString(capability.capabilityId))
2173
+ issues.push(`${entryPrefix}.capabilityId must be a non-empty string`);
2174
+ if (!Array.isArray(capability.memberNodeIds) || !isSortedUniqueStrings(capability.memberNodeIds))
2175
+ issues.push(`${entryPrefix}.memberNodeIds must be sorted and unique`);
2176
+ if (!isDigest(capability.semanticFingerprint))
2177
+ issues.push(`${entryPrefix}.semanticFingerprint must be a SHA-256 digest`);
2178
+ if (!isDigest(capability.flowProofFingerprint))
2179
+ issues.push(`${entryPrefix}.flowProofFingerprint must be a SHA-256 digest`);
2180
+ if (withSelectorEvidence && !isDigest(capability.selectorEvidenceDigest))
2181
+ issues.push(`${entryPrefix}.selectorEvidenceDigest must be a SHA-256 digest`);
2182
+ if (!isArchitectureCapabilityProofStatus(capability.proofStatus))
2183
+ issues.push(`${entryPrefix}.proofStatus must be a P1/P2 proof status`);
2184
+ const facets = record2(capability.facets);
2185
+ if (!facets)
2186
+ issues.push(`${entryPrefix}.facets must be an object`);
2187
+ else {
2188
+ issues.push(...exactKeys(facets, [...ARCHITECTURE_SEMANTIC_FACETS], [], `${entryPrefix}.facets`));
2189
+ for (const facet of ARCHITECTURE_SEMANTIC_FACETS) {
2190
+ if (!isDigest(facets[facet]))
2191
+ issues.push(`${entryPrefix}.facets.${facet} must be a SHA-256 digest`);
2192
+ }
2193
+ }
2194
+ });
2195
+ return issues;
2196
+ }
2197
+ function generatedFromIssues(value, prefix) {
2198
+ const generatedFrom = record2(value);
2199
+ if (!generatedFrom)
2200
+ return [`${prefix} must be an object`];
2201
+ const issues = exactKeys(generatedFrom, ["codeGraphPackage", "codeGraphVersion"], [], prefix);
2202
+ for (const field of ["codeGraphPackage", "codeGraphVersion"]) {
2203
+ if (!isNonEmptyString(generatedFrom[field]))
2204
+ issues.push(`${prefix}.${field} must be a non-empty string`);
2205
+ }
2206
+ return issues;
2207
+ }
2208
+ function canonicalCapability(capability) {
2209
+ return {
2210
+ capabilityId: capability.capabilityId,
2211
+ memberNodeIds: [...capability.memberNodeIds],
2212
+ semanticFingerprint: capability.semanticFingerprint,
2213
+ flowProofFingerprint: capability.flowProofFingerprint,
2214
+ proofStatus: { p1: capability.proofStatus.p1, p2: capability.proofStatus.p2 },
2215
+ facets: Object.fromEntries(Object.keys(capability.facets).sort(compareStrings).map((facet) => [facet, capability.facets[facet]])),
2216
+ selectorEvidenceDigest: capability.selectorEvidenceDigest
2217
+ };
2218
+ }
2219
+ function canonicalTargetRow(row) {
2220
+ return {
2221
+ type: row.type,
2222
+ scope: {
2223
+ kind: row.scope.kind,
2224
+ ...row.scope.id !== undefined ? { id: row.scope.id } : {},
2225
+ ...row.scope.entityKind !== undefined ? { entityKind: row.scope.entityKind } : {}
2226
+ },
2227
+ path: row.path,
2228
+ ownership: row.ownership,
2229
+ format: row.format,
2230
+ outputDigest: row.outputDigest,
2231
+ ...row.sourceStamps !== undefined ? { sourceStamps: Object.fromEntries(Object.keys(row.sourceStamps).sort(compareStrings).map((nodeId) => [nodeId, row.sourceStamps[nodeId]])) } : {},
2232
+ ...row.scale !== undefined ? {
2233
+ scale: {
2234
+ fileCountBucket: { lower: row.scale.fileCountBucket.lower, upper: row.scale.fileCountBucket.upper },
2235
+ lineCountBucket: { lower: row.scale.lineCountBucket.lower, upper: row.scale.lineCountBucket.upper }
2236
+ }
2237
+ } : {}
2238
+ };
2239
+ }
2240
+ function isArchitectureScaleBucket(value) {
2241
+ const bucket = record2(value);
2242
+ if (!bucket || Object.keys(bucket).length !== 2)
2243
+ return false;
2244
+ const { lower, upper } = bucket;
2245
+ if (typeof lower !== "number" || typeof upper !== "number" || !Number.isSafeInteger(lower) || !Number.isSafeInteger(upper))
2246
+ return false;
2247
+ if (lower === 0)
2248
+ return upper === 1;
2249
+ let magnitude = 1;
2250
+ while (magnitude * 10 <= lower)
2251
+ magnitude *= 10;
2252
+ const mantissa = lower / magnitude;
2253
+ if (mantissa === 1)
2254
+ return upper === 2 * magnitude;
2255
+ if (mantissa === 2)
2256
+ return upper === 5 * magnitude;
2257
+ if (mantissa === 5)
2258
+ return upper === 10 * magnitude;
2259
+ return false;
2260
+ }
2261
+ function manifestTargetIssues(value, prefix) {
2262
+ const target = record2(value);
2263
+ if (!target)
2264
+ return [`${prefix} must be an object`];
2265
+ const issues = exactKeys(target, ["type", "scope", "path", "ownership", "format", "outputDigest"], ["sourceStamps", "scale"], prefix);
2266
+ if (typeof target.type !== "string" || !Object.hasOwn(TARGET_TYPES, target.type))
2267
+ issues.push(`${prefix}.type is unsupported`);
2268
+ const scope = record2(target.scope);
2269
+ if (!scope || typeof scope.kind !== "string" || !Object.hasOwn(SCOPE_KINDS, scope.kind))
2270
+ issues.push(`${prefix}.scope.kind is unsupported`);
2271
+ else {
2272
+ issues.push(...exactKeys(scope, ["kind"], ["id", "entityKind"], `${prefix}.scope`));
2273
+ for (const field of ["id", "entityKind"]) {
2274
+ if (scope[field] !== undefined && typeof scope[field] !== "string")
2275
+ issues.push(`${prefix}.scope.${field} must be a string`);
2276
+ }
2277
+ }
2278
+ if (typeof target.path !== "string" || !isRepoRelativePosixPath(target.path))
2279
+ issues.push(`${prefix}.path must be a repository-relative POSIX path`);
2280
+ if (typeof target.ownership !== "string" || !Object.hasOwn(OWNERSHIPS, target.ownership))
2281
+ issues.push(`${prefix}.ownership is unsupported`);
2282
+ if (typeof target.format !== "string" || !Object.hasOwn(FORMATS, target.format))
2283
+ issues.push(`${prefix}.format is unsupported`);
2284
+ if (!isDigest(target.outputDigest))
2285
+ issues.push(`${prefix}.outputDigest must be a SHA-256 digest`);
2286
+ if (target.sourceStamps !== undefined && target.type !== "entity-summary" && !isRuntimeTopologyTargetType(target.type)) {
2287
+ issues.push(`${prefix}.sourceStamps are only allowed on entity-summary and runtime topology targets`);
2288
+ }
2289
+ if (target.scale !== undefined && target.type !== "entity-summary")
2290
+ issues.push(`${prefix}.scale is only allowed on entity-summary targets`);
2291
+ if (target.sourceStamps !== undefined) {
2292
+ const stamps = record2(target.sourceStamps);
2293
+ if (!stamps || Object.keys(stamps).length === 0)
2294
+ issues.push(`${prefix}.sourceStamps must be a non-empty object keyed by node id`);
2295
+ else {
2296
+ for (const [nodeId, digest] of Object.entries(stamps)) {
2297
+ if (!isNonEmptyString(nodeId))
2298
+ issues.push(`${prefix}.sourceStamps keys must be non-empty node ids`);
2299
+ if (!isDigest(digest))
2300
+ issues.push(`${prefix}.sourceStamps.${nodeId} must be a SHA-256 digest`);
2301
+ }
2302
+ }
2303
+ }
2304
+ const ownNodeId = scope?.id;
2305
+ const stampsOwnNode = typeof ownNodeId === "string" && record2(target.sourceStamps) !== undefined && Object.hasOwn(record2(target.sourceStamps), ownNodeId);
2306
+ if (stampsOwnNode !== (target.scale !== undefined))
2307
+ issues.push(`${prefix}.scale must be present exactly when sourceStamps stamps the target's own node`);
2308
+ if (target.scale !== undefined) {
2309
+ const scale = record2(target.scale);
2310
+ if (!scale)
2311
+ issues.push(`${prefix}.scale must be an object`);
2312
+ else {
2313
+ issues.push(...exactKeys(scale, ["fileCountBucket", "lineCountBucket"], [], `${prefix}.scale`));
2314
+ for (const field of ["fileCountBucket", "lineCountBucket"]) {
2315
+ if (!isArchitectureScaleBucket(scale[field]))
2316
+ issues.push(`${prefix}.scale.${field} must be a 1-2-5 magnitude bucket`);
2317
+ }
2318
+ }
2319
+ }
2320
+ return issues;
2321
+ }
2322
+ function record2(value) {
2323
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
2324
+ }
2325
+ function exactKeys(value, required, optional, prefix) {
2326
+ const issues = required.filter((key) => !(key in value)).map((key) => `${prefix}.${key} is required`);
2327
+ const allowed = new Set([...required, ...optional]);
2328
+ for (const key of Object.keys(value))
2329
+ if (!allowed.has(key))
2330
+ issues.push(`${prefix}.${key} is not allowed`);
2331
+ return issues;
2332
+ }
2333
+ function isDigest(value) {
2334
+ return typeof value === "string" && SHA256.test(value);
2335
+ }
2336
+ function isNonEmptyString(value) {
2337
+ return typeof value === "string" && value.trim() !== "";
2338
+ }
2339
+ function isSortedUniqueStrings(values) {
2340
+ return values.every((value, index) => typeof value === "string" && (index === 0 || values[index - 1] < value));
2341
+ }
2342
+ function compareStrings(left, right) {
2343
+ return left < right ? -1 : left > right ? 1 : 0;
2344
+ }
2345
+ function versionNumber(value, family) {
2346
+ if (typeof value !== "string" || !value.startsWith(family))
2347
+ return;
2348
+ const suffix = value.slice(family.length);
2349
+ if (!/^[1-9][0-9]*$/.test(suffix))
2350
+ return;
2351
+ const version = Number(suffix);
2352
+ return Number.isSafeInteger(version) ? version : undefined;
2353
+ }
2354
+ function architectureDocsProjectionCompatibilityIssues(value, engine = {
2355
+ rendererVersion: ARCHITECTURE_DOCS_RENDERER_VERSION,
2356
+ protocolVersion: PROJECTION_REQUEST_SCHEMA_VERSION
2357
+ }) {
2358
+ const manifest = record2(value);
2359
+ if (!manifest)
2360
+ return [];
2361
+ const issues = [];
2362
+ if (["minimumRendererVersion", "minimumProtocolVersion"].some((key) => Object.hasOwn(manifest, key)) && manifest.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION)
2363
+ issues.push("projection manifest floors require the current schema");
2364
+ if (typeof manifest.schemaVersion === "string" && manifest.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION && !isSupersededArchitectureDocsProjectionManifestSchemaVersion(manifest.schemaVersion))
2365
+ issues.push("projection manifest schema is unsupported by this engine");
2366
+ for (const [key, family, current] of [
2367
+ ["minimumRendererVersion", "archcontext.docs-renderer/v", engine.rendererVersion],
2368
+ ["minimumProtocolVersion", "archcontext.projection-request/v", engine.protocolVersion]
2369
+ ]) {
2370
+ if (!Object.hasOwn(manifest, key))
2371
+ continue;
2372
+ const required = versionNumber(manifest[key], family);
2373
+ const supported = versionNumber(current, family);
2374
+ if (required === undefined || supported === undefined || supported < required)
2375
+ issues.push(`projection manifest ${key} is unsupported by this engine`);
2376
+ }
2377
+ return issues;
2378
+ }
2379
+ var ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION = "archcontext.architecture-docs-projection-manifest/v3", SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS, ARCHITECTURE_DOCS_PROJECTION_MANIFEST_UPGRADE_COMMAND = "archctx docs apply --approved --profile <default|repo-harness/v1>", ARCHITECTURE_DOCS_PROJECTION_MANIFEST_MIGRATION_GUIDE = "docs/runbooks/architecture-documentation-projections.md", PROJECTION_MANIFEST_UPGRADE_REQUIRED = "projection-manifest-upgrade-required", PROJECTION_MANIFEST_INVALID = "projection-manifest-invalid", PROJECTION_FOOTPRINT_UNCOVERED = "projection-footprint-uncovered", ARCHITECTURE_DOCS_PROJECTION_PROVENANCE_SCHEMA_VERSION = "archcontext.architecture-docs-projection-provenance/v3", ARCHITECTURE_DOCS_LAYOUT_VERSION_V1 = "archcontext.docs-layout/v1", ARCHITECTURE_SEMANTIC_STATE_SCHEMA_VERSION = "archcontext.architecture-semantic-state/v1", ARCHITECTURE_DOCS_PROJECTION_PROFILES, SHA256, TARGET_TYPES, RUNTIME_TOPOLOGY_TARGET_TYPES, SCOPE_KINDS, OWNERSHIPS, FORMATS;
2380
+ var init_projection_manifest = __esm(() => {
2381
+ init_projection();
2382
+ init_schema();
2383
+ SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS = [
2384
+ "archcontext.architecture-docs-projection-manifest/v1",
2385
+ "archcontext.architecture-docs-projection-manifest/v2"
2386
+ ];
2387
+ ARCHITECTURE_DOCS_PROJECTION_PROFILES = ["default", "repo-harness/v1"];
2388
+ SHA256 = /^sha256:[a-f0-9]{64}$/;
2389
+ TARGET_TYPES = {
2390
+ "architecture-index": true,
2391
+ "entity-summary": true,
2392
+ "relation-summary": true,
2393
+ "decision-index": true,
2394
+ "architecture-changelog": true,
2395
+ "diagram-mermaid": true,
2396
+ "diagram-structurizr": true,
2397
+ "diagram-likec4": true,
2398
+ "diagram-runtime-topology": true,
2399
+ "runtime-topology-summary": true,
2400
+ "agent-context": true
2401
+ };
2402
+ RUNTIME_TOPOLOGY_TARGET_TYPES = ["diagram-runtime-topology", "runtime-topology-summary"];
2403
+ SCOPE_KINDS = { repository: true, entity: true, relation: true, decision: true, diagram: true, changelog: true };
2404
+ OWNERSHIPS = { generated: true, mixed: true };
2405
+ FORMATS = { markdown: true, mermaid: true, "structurizr-json": true, likec4: true };
2406
+ });
2407
+
1964
2408
  // packages/contracts/src/projection-recovery.ts
1965
2409
  function jsonDataCopy(input, maximum) {
1966
2410
  let measured = 0;
@@ -2085,7 +2529,7 @@ var init_projection_recovery = __esm(() => {
2085
2529
  // packages/contracts/src/failure.ts
2086
2530
  import { isNativeError } from "node:util/types";
2087
2531
  function ownData(input, key) {
2088
- if (!record2(input))
2532
+ if (!record3(input))
2089
2533
  throw new Error("Failure metadata must be an object");
2090
2534
  const descriptor = Object.getOwnPropertyDescriptor(input, key);
2091
2535
  if (!descriptor) {
@@ -2133,7 +2577,7 @@ function detailsFor(policy, input) {
2133
2577
  if (policy.facts)
2134
2578
  return localFactsFor(policy.facts, input);
2135
2579
  const result = {};
2136
- if (!record2(input))
2580
+ if (!record3(input))
2137
2581
  throw new Error("Failure details must be an object");
2138
2582
  let omitted = 0;
2139
2583
  for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(input))) {
@@ -2159,7 +2603,7 @@ function detailsFor(policy, input) {
2159
2603
  return result;
2160
2604
  }
2161
2605
  function dataRecord(value) {
2162
- if (!record2(value))
2606
+ if (!record3(value))
2163
2607
  throw new Error("Facts must be a plain record");
2164
2608
  const proto = Object.getPrototypeOf(value), keys = Reflect.ownKeys(value);
2165
2609
  if (proto !== Object.prototype && proto !== null || keys.length > 16 || Object.keys(value).length !== keys.length || keys.some((key) => typeof key !== "string"))
@@ -2284,7 +2728,7 @@ function nativeFactsFor(policy, input) {
2284
2728
  let omitted = 0, characters = 0;
2285
2729
  const omit = (value) => {
2286
2730
  omitted++;
2287
- const strings = (v) => typeof v === "string" ? v.length : Array.isArray(v) ? v.reduce((n, item) => n + strings(item), 0) : record2(v) ? Object.values(v).reduce((n, item) => n + strings(item), 0) : 0;
2731
+ const strings = (v) => typeof v === "string" ? v.length : Array.isArray(v) ? v.reduce((n, item) => n + strings(item), 0) : record3(v) ? Object.values(v).reduce((n, item) => n + strings(item), 0) : 0;
2288
2732
  characters += strings(value);
2289
2733
  };
2290
2734
  const text = (value) => {
@@ -2423,7 +2867,7 @@ function budgetIssues(value, depth = 0, maxStringBytes = 256) {
2423
2867
  return Number.isFinite(value) ? [] : ["detail number is not finite"];
2424
2868
  if (Array.isArray(value))
2425
2869
  return value.length <= 32 ? value.flatMap((item) => budgetIssues(item, depth + 1, maxStringBytes)) : ["detail list exceeds 32"];
2426
- if (record2(value))
2870
+ if (record3(value))
2427
2871
  return Object.keys(value).length <= 16 ? Object.values(value).flatMap((item) => budgetIssues(item, depth + 1, maxStringBytes)) : ["detail object exceeds 16 fields"];
2428
2872
  return value === null || typeof value === "boolean" ? [] : ["detail value is not JSON"];
2429
2873
  }
@@ -2498,7 +2942,7 @@ function toEnvelope(requestId, error, stage) {
2498
2942
  }
2499
2943
  }
2500
2944
  function normalizeFailureResult(result, stage, requestId = "failure") {
2501
- if (!record2(result))
2945
+ if (!record3(result))
2502
2946
  return result;
2503
2947
  try {
2504
2948
  if (ownData(result, "ok") !== false)
@@ -2528,7 +2972,7 @@ function jsonDataSnapshot(value, depth = 0, maxStringBytes = 256) {
2528
2972
  return jsonDataSnapshot(descriptor.value, depth + 1, maxStringBytes);
2529
2973
  });
2530
2974
  }
2531
- if (record2(value)) {
2975
+ if (record3(value)) {
2532
2976
  const prototype = Object.getPrototypeOf(value);
2533
2977
  const keys = Reflect.ownKeys(value);
2534
2978
  if (prototype !== Object.prototype && prototype !== null || keys.length > 16 || Object.keys(value).length !== keys.length || keys.some((key) => typeof key !== "string"))
@@ -2539,7 +2983,7 @@ function jsonDataSnapshot(value, depth = 0, maxStringBytes = 256) {
2539
2983
  }
2540
2984
  function failureIssues(value) {
2541
2985
  try {
2542
- if (!record2(value))
2986
+ if (!record3(value))
2543
2987
  return ["failure must be an object"];
2544
2988
  const fields = ["code", "message", "severity", "retryable", "action", "reasonCode", "details"];
2545
2989
  const keys = Reflect.ownKeys(value);
@@ -2558,10 +3002,12 @@ function failureIssues(value) {
2558
3002
  return ["failure violates its registered contract or budget"];
2559
3003
  }
2560
3004
  }
2561
- var FAILURE_STAGES, ERROR_CLASSES, CODE_FACTS_ISSUE_MESSAGES, policies, FAILURE_POLICIES, catalogDefaults, actions, bytes = (value) => new TextEncoder().encode(value).byteLength, record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), finiteNonnegative = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0, criticalKey = (key) => /id$|digest|receipt|binding|readback|lookupkey/i.test(key), localEnums, nativeEnums, nativeDiagnosticKinds, FailureError;
3005
+ var FAILURE_STAGES, ERROR_CLASSES, CODE_FACTS_ISSUE_MESSAGES, policies, FAILURE_POLICIES, catalogDefaults, actions, bytes = (value) => new TextEncoder().encode(value).byteLength, record3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), finiteNonnegative = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0, criticalKey = (key) => /id$|digest|receipt|binding|readback|lookupkey/i.test(key), localEnums, nativeEnums, nativeDiagnosticKinds, FailureError;
2562
3006
  var init_failure = __esm(() => {
2563
3007
  init_changeset_recovery();
2564
3008
  init_ports();
3009
+ init_projection();
3010
+ init_projection_manifest();
2565
3011
  init_projection_recovery();
2566
3012
  init_schema();
2567
3013
  FAILURE_STAGES = Object.freeze(["debt", "complete", "practice-checkpoint", "cli", "mcp", "hook-checkpoint", "failure-metadata", "public-operation", "native-export", "docs-anchors", "flows-check"]);
@@ -2589,7 +3035,7 @@ var init_failure = __esm(() => {
2589
3035
  "model-missing": { code: "AC_MODEL_ADOPTION_REQUIRED", message: "Architecture debt requires an adopted model.", fields: ["checks"] },
2590
3036
  "changed-path-invalid": { code: "AC_SCHEMA_INVALID", message: "Changed paths must be an array of repository-relative POSIX paths.", fields: ["checks"] },
2591
3037
  "debt-report-invalid": { code: "AC_SCHEMA_INVALID", message: "Architecture debt evidence violates its contract.", fields: ["checks"] },
2592
- "projection-manifest-upgrade-required": { code: "AC_PRECONDITION_FAILED", message: "The committed projection manifest requires supported re-baselining. First restore the original model if missing; the manifest digest cannot recover it. With the reviewed model available, follow docs/runbooks/architecture-documentation-projections.md before running archctx docs apply --approved --profile <default|repo-harness/v1>." },
3038
+ "projection-manifest-upgrade-required": { code: "AC_PRECONDITION_FAILED", message: `The committed projection manifest requires supported re-baselining. First restore the original model if missing; the manifest digest cannot recover it. With the reviewed model available, follow ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_MIGRATION_GUIDE} before running ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_UPGRADE_COMMAND}.`, facts: { manifestPath: "optional:projectionManifestPath", foundSchemaVersion: "optional:projectionManifestSchemaVersion", supportedSchemaVersion: "optional:projectionManifestSchemaVersion", upgradeCommand: "optional:projectionManifestUpgradeCommand", migrationGuide: "optional:projectionManifestMigrationGuide" } },
2593
3039
  "projection-manifest-invalid": { code: "AC_PRECONDITION_FAILED", message: "The committed projection manifest violates its contract." },
2594
3040
  "architecture-model-ignored": { code: "AC_PRECONDITION_FAILED", action: "commit-architecture-model", message: "Git ignore rules exclude architecture model paths, so the model cannot be committed and a manifest digest cannot rebuild it. Remove or narrow the rule, commit the model, then retry adoption. The diagnostic command prints each deciding rule.", facts: { pathCount: "uint", paths: "optional:diagnosticPaths", commands: "optional:diagnosticCommands", omittedPathCount: "uint" } },
2595
3041
  "projection-footprint-uncovered": { code: "AC_PRECONDITION_FAILED", message: "Declared source footprints lack a projection target." },
@@ -2850,6 +3296,10 @@ var init_failure = __esm(() => {
2850
3296
  upgradeAction: ["upgrade-archctx-runtime"],
2851
3297
  upgradeCommand: ["archctx daemon upgrade"],
2852
3298
  ownershipAction: ["remove-whole-file-outputs-and-reapply"],
3299
+ projectionManifestPath: [ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH],
3300
+ projectionManifestSchemaVersion: [...SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS, ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION],
3301
+ projectionManifestUpgradeCommand: [ARCHITECTURE_DOCS_PROJECTION_MANIFEST_UPGRADE_COMMAND],
3302
+ projectionManifestMigrationGuide: [ARCHITECTURE_DOCS_PROJECTION_MANIFEST_MIGRATION_GUIDE],
2853
3303
  ledgerModeField: ["rolloutMode", "readMode", "writeMode"],
2854
3304
  depsField: ["from", "into", "importNodeLimit", "edgeLimit"],
2855
3305
  depsIssue: ["unknown-node", "invalid-limit", "missing-value"],
@@ -3566,450 +4016,6 @@ var PRACTICE_SCHEMA_VERSION = "archcontext.practice/v1", PRACTICE_PROFILE_SCHEMA
3566
4016
  var PROJECTION_PUBLISH_RUN_SCHEMA_VERSION = "archcontext.projection-publish-run/v1", PROJECTION_PUBLISH_STATUS_SCHEMA_VERSION = "archcontext.projection-publish-status/v1", PROJECTION_PR_VERIFICATION_SCHEMA_VERSION = "archcontext.projection-pr-verification/v1", PROJECTION_WRITER_BRANCH_PREFIX = "archctx/", PROJECTION_WRITER_DEFAULT_BRANCH = "archctx/projection";
3567
4017
  var init_projection_writer = () => {};
3568
4018
 
3569
- // packages/contracts/src/projection-manifest.ts
3570
- function isRuntimeTopologyTargetType(type) {
3571
- return typeof type === "string" && RUNTIME_TOPOLOGY_TARGET_TYPES.includes(type);
3572
- }
3573
- function architectureDocsProjectionManifestIssues(value) {
3574
- const issues = [];
3575
- const manifest = record3(value);
3576
- if (!manifest)
3577
- return ["manifest must be an object"];
3578
- issues.push(...exactKeys(manifest, ["schemaVersion", "rendererVersion", "profile", "layoutVersion", "generatedFrom", "semanticBaseline", "targets"], ["minimumRendererVersion", "minimumProtocolVersion"], "manifest"));
3579
- if (manifest.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION)
3580
- issues.push("manifest.schemaVersion is unsupported");
3581
- if (!isNonEmptyString(manifest.rendererVersion))
3582
- issues.push("manifest.rendererVersion must be a non-empty string");
3583
- for (const [key, family] of [["minimumRendererVersion", "archcontext.docs-renderer/v"], ["minimumProtocolVersion", "archcontext.projection-request/v"]]) {
3584
- if (Object.hasOwn(manifest, key) && versionNumber(manifest[key], family) === undefined)
3585
- issues.push(`manifest.${key} must name a supported version family`);
3586
- }
3587
- if (!ARCHITECTURE_DOCS_PROJECTION_PROFILES.includes(manifest.profile))
3588
- issues.push("manifest.profile is unsupported");
3589
- if (manifest.layoutVersion !== ARCHITECTURE_DOCS_LAYOUT_VERSION_V1)
3590
- issues.push("manifest.layoutVersion is unsupported");
3591
- issues.push(...generatedFromIssues(manifest.generatedFrom, "manifest.generatedFrom"));
3592
- const baseline = record3(manifest.semanticBaseline);
3593
- if (!baseline)
3594
- issues.push("manifest.semanticBaseline must be an object");
3595
- else {
3596
- issues.push(...exactKeys(baseline, ["modelDigest", "capabilities"], [], "manifest.semanticBaseline"));
3597
- if (!isDigest(baseline.modelDigest))
3598
- issues.push("manifest.semanticBaseline.modelDigest must be a SHA-256 digest");
3599
- issues.push(...capabilityEntriesIssues(baseline.capabilities, "manifest.semanticBaseline.capabilities", true));
3600
- }
3601
- const targets = record3(manifest.targets);
3602
- if (!targets) {
3603
- issues.push("manifest.targets must be an object keyed by targetId");
3604
- return issues;
3605
- }
3606
- const paths = new Set;
3607
- const stampOwners = new Map;
3608
- let topologyStamps;
3609
- for (const [targetId, row] of Object.entries(targets)) {
3610
- const prefix = `manifest.targets[${JSON.stringify(targetId)}]`;
3611
- if (!isNonEmptyString(targetId))
3612
- issues.push("manifest.targets keys must be non-empty targetIds");
3613
- issues.push(...manifestTargetIssues(row, prefix));
3614
- const path = record3(row)?.path;
3615
- if (typeof path === "string") {
3616
- if (paths.has(path))
3617
- issues.push(`${prefix}.path is recorded by another target`);
3618
- paths.add(path);
3619
- }
3620
- const stamps = record3(record3(row)?.sourceStamps) ?? {};
3621
- if (isRuntimeTopologyTargetType(record3(row)?.type)) {
3622
- const serialized = JSON.stringify(Object.keys(stamps).sort(compareStrings).map((nodeId) => [nodeId, stamps[nodeId]]));
3623
- if (topologyStamps === undefined)
3624
- topologyStamps = { targetId, stamps: serialized };
3625
- else if (topologyStamps.stamps !== serialized)
3626
- issues.push(`${prefix}.sourceStamps must equal the sourceStamps of ${topologyStamps.targetId}`);
3627
- for (const nodeId of Object.keys(stamps)) {
3628
- const owner = stampOwners.get(nodeId);
3629
- if (owner !== undefined && !isRuntimeTopologyTargetType(record3(targets[owner])?.type))
3630
- issues.push(`${prefix}.sourceStamps.${nodeId} is already stamped on ${owner}`);
3631
- else if (owner === undefined)
3632
- stampOwners.set(nodeId, targetId);
3633
- }
3634
- continue;
3635
- }
3636
- for (const nodeId of Object.keys(stamps)) {
3637
- const owner = stampOwners.get(nodeId);
3638
- if (owner !== undefined)
3639
- issues.push(`${prefix}.sourceStamps.${nodeId} is already stamped on ${owner}`);
3640
- else
3641
- stampOwners.set(nodeId, targetId);
3642
- }
3643
- }
3644
- return issues;
3645
- }
3646
- function architectureDocsProjectionManifestSchemaVersion(body) {
3647
- let parsed;
3648
- try {
3649
- parsed = JSON.parse(body);
3650
- } catch {
3651
- return;
3652
- }
3653
- const schemaVersion = record3(parsed)?.schemaVersion;
3654
- return typeof schemaVersion === "string" ? schemaVersion : undefined;
3655
- }
3656
- function isSupersededArchitectureDocsProjectionManifestSchemaVersion(schemaVersion) {
3657
- return SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS.includes(schemaVersion);
3658
- }
3659
- function serializeArchitectureDocsProjectionManifest(manifest) {
3660
- const capabilities = [...manifest.semanticBaseline.capabilities].sort((left, right) => compareStrings(left.capabilityId, right.capabilityId)).map(canonicalCapability);
3661
- const capabilityBlock = JSON.stringify(capabilities, null, 2).split(`
3662
- `).map((line, index) => index === 0 ? line : ` ${line}`).join(`
3663
- `);
3664
- const targetIds = Object.keys(manifest.targets).sort(compareStrings);
3665
- const targetLines = targetIds.length === 0 ? [' "targets": {}'] : [
3666
- ' "targets": {',
3667
- ...targetIds.flatMap((targetId, index) => [
3668
- ` ${JSON.stringify(targetId)}:`,
3669
- ` ${JSON.stringify(canonicalTargetRow(manifest.targets[targetId]))}${index === targetIds.length - 1 ? "" : ","}`
3670
- ]),
3671
- " }"
3672
- ];
3673
- return [
3674
- "{",
3675
- ` "schemaVersion": ${JSON.stringify(manifest.schemaVersion)},`,
3676
- ` "rendererVersion": ${JSON.stringify(manifest.rendererVersion)},`,
3677
- ...manifest.minimumRendererVersion === undefined ? [] : [` "minimumRendererVersion": ${JSON.stringify(manifest.minimumRendererVersion)},`],
3678
- ...manifest.minimumProtocolVersion === undefined ? [] : [` "minimumProtocolVersion": ${JSON.stringify(manifest.minimumProtocolVersion)},`],
3679
- ` "profile": ${JSON.stringify(manifest.profile)},`,
3680
- ` "layoutVersion": ${JSON.stringify(manifest.layoutVersion)},`,
3681
- ` "generatedFrom": ${JSON.stringify({ codeGraphPackage: manifest.generatedFrom.codeGraphPackage, codeGraphVersion: manifest.generatedFrom.codeGraphVersion })},`,
3682
- ' "semanticBaseline": {',
3683
- ` "modelDigest": ${JSON.stringify(manifest.semanticBaseline.modelDigest)},`,
3684
- ` "capabilities": ${capabilityBlock}`,
3685
- " },",
3686
- ...targetLines,
3687
- "}",
3688
- ""
3689
- ].join(`
3690
- `);
3691
- }
3692
- function architectureDocsProjectionManifestSemanticState(manifest) {
3693
- return architectureSemanticStateFromCapabilities(manifest.semanticBaseline.capabilities.map(({ selectorEvidenceDigest: _selectorEvidenceDigest, ...capability }) => capability));
3694
- }
3695
- function architectureSemanticStateFromCapabilities(capabilities) {
3696
- const sorted = [...capabilities].sort((left, right) => compareStrings(left.capabilityId, right.capabilityId));
3697
- return {
3698
- schemaVersion: ARCHITECTURE_SEMANTIC_STATE_SCHEMA_VERSION,
3699
- capabilities: sorted,
3700
- semanticFingerprint: digestJson(sorted.map(({ capabilityId, semanticFingerprint }) => ({ capabilityId, semanticFingerprint }))),
3701
- flowProofFingerprint: digestJson(sorted.map(({ capabilityId, flowProofFingerprint }) => ({ capabilityId, flowProofFingerprint })))
3702
- };
3703
- }
3704
- function architectureDocsProjectionManifestSourceStamps(manifest) {
3705
- const stamps = {};
3706
- for (const row of Object.values(manifest.targets))
3707
- Object.assign(stamps, row.sourceStamps ?? {});
3708
- return stamps;
3709
- }
3710
- function architectureDocsProjectionManifestProofEvidence(manifest) {
3711
- return {
3712
- rendererVersion: manifest.rendererVersion,
3713
- selectorEvidenceDigests: Object.fromEntries(manifest.semanticBaseline.capabilities.map((capability) => [capability.capabilityId, capability.selectorEvidenceDigest])),
3714
- sourceStamps: architectureDocsProjectionManifestSourceStamps(manifest)
3715
- };
3716
- }
3717
- function architectureSourceStampsDigest(stamps) {
3718
- return digestJson({
3719
- schemaVersion: "archcontext.architecture-source-stamps/v1",
3720
- stamps: Object.keys(stamps).sort(compareStrings).map((nodeId) => ({ nodeId, digest: stamps[nodeId] }))
3721
- });
3722
- }
3723
- function architectureProjectionOutputsDigest(input) {
3724
- return digestJson({
3725
- schemaVersion: "archcontext.architecture-projection-outputs/v1",
3726
- rendererVersion: input.rendererVersion,
3727
- profile: input.profile,
3728
- outputs: Object.keys(input.outputDigests).sort(compareStrings).map((targetId) => ({ targetId, outputDigest: input.outputDigests[targetId] }))
3729
- });
3730
- }
3731
- function architectureDocsProjectionManifestDigests(manifest) {
3732
- return {
3733
- modelDigest: manifest.semanticBaseline.modelDigest,
3734
- sourceTreeDigest: architectureSourceStampsDigest(architectureDocsProjectionManifestSourceStamps(manifest)),
3735
- flowProofDigest: architectureDocsProjectionManifestSemanticState(manifest).flowProofFingerprint,
3736
- projectionDigest: architectureProjectionOutputsDigest({
3737
- rendererVersion: manifest.rendererVersion,
3738
- profile: manifest.profile,
3739
- outputDigests: Object.fromEntries(Object.entries(manifest.targets).map(([targetId, row]) => [targetId, row.outputDigest]))
3740
- })
3741
- };
3742
- }
3743
- function architectureDocsProjectionProvenanceIssues(value, prefix = "provenance") {
3744
- const provenance = record3(value);
3745
- if (!provenance)
3746
- return [`${prefix} must be an object`];
3747
- const issues = exactKeys(provenance, ["schemaVersion", "sourceTreeDigest", "modelDigest", "projectionInputDigest", "rendererVersion", "layoutVersion", "generatedFrom"], [], prefix);
3748
- if (provenance.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_PROVENANCE_SCHEMA_VERSION)
3749
- issues.push(`${prefix}.schemaVersion is unsupported`);
3750
- for (const field of ["sourceTreeDigest", "modelDigest", "projectionInputDigest"]) {
3751
- if (!isDigest(provenance[field]))
3752
- issues.push(`${prefix}.${field} must be a SHA-256 digest`);
3753
- }
3754
- if (provenance.rendererVersion !== ARCHITECTURE_DOCS_RENDERER_VERSION)
3755
- issues.push(`${prefix}.rendererVersion must be ${ARCHITECTURE_DOCS_RENDERER_VERSION}`);
3756
- if (provenance.layoutVersion !== ARCHITECTURE_DOCS_LAYOUT_VERSION_V1)
3757
- issues.push(`${prefix}.layoutVersion is unsupported`);
3758
- issues.push(...generatedFromIssues(provenance.generatedFrom, `${prefix}.generatedFrom`));
3759
- return issues;
3760
- }
3761
- function capabilityEntriesIssues(value, prefix, withSelectorEvidence) {
3762
- if (!Array.isArray(value))
3763
- return [`${prefix} must be an array`];
3764
- const issues = [];
3765
- const ids = value.map((entry) => record3(entry)?.capabilityId);
3766
- if (!isSortedUniqueStrings(ids))
3767
- issues.push(`${prefix} must be sorted and unique by capabilityId`);
3768
- value.forEach((entry, index) => {
3769
- const entryPrefix = `${prefix}[${index}]`;
3770
- const capability = record3(entry);
3771
- if (!capability) {
3772
- issues.push(`${entryPrefix} must be an object`);
3773
- return;
3774
- }
3775
- const required = ["capabilityId", "memberNodeIds", "semanticFingerprint", "flowProofFingerprint", "proofStatus", "facets", ...withSelectorEvidence ? ["selectorEvidenceDigest"] : []];
3776
- issues.push(...exactKeys(capability, required, [], entryPrefix));
3777
- if (!isNonEmptyString(capability.capabilityId))
3778
- issues.push(`${entryPrefix}.capabilityId must be a non-empty string`);
3779
- if (!Array.isArray(capability.memberNodeIds) || !isSortedUniqueStrings(capability.memberNodeIds))
3780
- issues.push(`${entryPrefix}.memberNodeIds must be sorted and unique`);
3781
- if (!isDigest(capability.semanticFingerprint))
3782
- issues.push(`${entryPrefix}.semanticFingerprint must be a SHA-256 digest`);
3783
- if (!isDigest(capability.flowProofFingerprint))
3784
- issues.push(`${entryPrefix}.flowProofFingerprint must be a SHA-256 digest`);
3785
- if (withSelectorEvidence && !isDigest(capability.selectorEvidenceDigest))
3786
- issues.push(`${entryPrefix}.selectorEvidenceDigest must be a SHA-256 digest`);
3787
- if (!isArchitectureCapabilityProofStatus(capability.proofStatus))
3788
- issues.push(`${entryPrefix}.proofStatus must be a P1/P2 proof status`);
3789
- const facets = record3(capability.facets);
3790
- if (!facets)
3791
- issues.push(`${entryPrefix}.facets must be an object`);
3792
- else {
3793
- issues.push(...exactKeys(facets, [...ARCHITECTURE_SEMANTIC_FACETS], [], `${entryPrefix}.facets`));
3794
- for (const facet of ARCHITECTURE_SEMANTIC_FACETS) {
3795
- if (!isDigest(facets[facet]))
3796
- issues.push(`${entryPrefix}.facets.${facet} must be a SHA-256 digest`);
3797
- }
3798
- }
3799
- });
3800
- return issues;
3801
- }
3802
- function generatedFromIssues(value, prefix) {
3803
- const generatedFrom = record3(value);
3804
- if (!generatedFrom)
3805
- return [`${prefix} must be an object`];
3806
- const issues = exactKeys(generatedFrom, ["codeGraphPackage", "codeGraphVersion"], [], prefix);
3807
- for (const field of ["codeGraphPackage", "codeGraphVersion"]) {
3808
- if (!isNonEmptyString(generatedFrom[field]))
3809
- issues.push(`${prefix}.${field} must be a non-empty string`);
3810
- }
3811
- return issues;
3812
- }
3813
- function canonicalCapability(capability) {
3814
- return {
3815
- capabilityId: capability.capabilityId,
3816
- memberNodeIds: [...capability.memberNodeIds],
3817
- semanticFingerprint: capability.semanticFingerprint,
3818
- flowProofFingerprint: capability.flowProofFingerprint,
3819
- proofStatus: { p1: capability.proofStatus.p1, p2: capability.proofStatus.p2 },
3820
- facets: Object.fromEntries(Object.keys(capability.facets).sort(compareStrings).map((facet) => [facet, capability.facets[facet]])),
3821
- selectorEvidenceDigest: capability.selectorEvidenceDigest
3822
- };
3823
- }
3824
- function canonicalTargetRow(row) {
3825
- return {
3826
- type: row.type,
3827
- scope: {
3828
- kind: row.scope.kind,
3829
- ...row.scope.id !== undefined ? { id: row.scope.id } : {},
3830
- ...row.scope.entityKind !== undefined ? { entityKind: row.scope.entityKind } : {}
3831
- },
3832
- path: row.path,
3833
- ownership: row.ownership,
3834
- format: row.format,
3835
- outputDigest: row.outputDigest,
3836
- ...row.sourceStamps !== undefined ? { sourceStamps: Object.fromEntries(Object.keys(row.sourceStamps).sort(compareStrings).map((nodeId) => [nodeId, row.sourceStamps[nodeId]])) } : {},
3837
- ...row.scale !== undefined ? {
3838
- scale: {
3839
- fileCountBucket: { lower: row.scale.fileCountBucket.lower, upper: row.scale.fileCountBucket.upper },
3840
- lineCountBucket: { lower: row.scale.lineCountBucket.lower, upper: row.scale.lineCountBucket.upper }
3841
- }
3842
- } : {}
3843
- };
3844
- }
3845
- function isArchitectureScaleBucket(value) {
3846
- const bucket = record3(value);
3847
- if (!bucket || Object.keys(bucket).length !== 2)
3848
- return false;
3849
- const { lower, upper } = bucket;
3850
- if (typeof lower !== "number" || typeof upper !== "number" || !Number.isSafeInteger(lower) || !Number.isSafeInteger(upper))
3851
- return false;
3852
- if (lower === 0)
3853
- return upper === 1;
3854
- let magnitude = 1;
3855
- while (magnitude * 10 <= lower)
3856
- magnitude *= 10;
3857
- const mantissa = lower / magnitude;
3858
- if (mantissa === 1)
3859
- return upper === 2 * magnitude;
3860
- if (mantissa === 2)
3861
- return upper === 5 * magnitude;
3862
- if (mantissa === 5)
3863
- return upper === 10 * magnitude;
3864
- return false;
3865
- }
3866
- function manifestTargetIssues(value, prefix) {
3867
- const target = record3(value);
3868
- if (!target)
3869
- return [`${prefix} must be an object`];
3870
- const issues = exactKeys(target, ["type", "scope", "path", "ownership", "format", "outputDigest"], ["sourceStamps", "scale"], prefix);
3871
- if (typeof target.type !== "string" || !Object.hasOwn(TARGET_TYPES, target.type))
3872
- issues.push(`${prefix}.type is unsupported`);
3873
- const scope = record3(target.scope);
3874
- if (!scope || typeof scope.kind !== "string" || !Object.hasOwn(SCOPE_KINDS, scope.kind))
3875
- issues.push(`${prefix}.scope.kind is unsupported`);
3876
- else {
3877
- issues.push(...exactKeys(scope, ["kind"], ["id", "entityKind"], `${prefix}.scope`));
3878
- for (const field of ["id", "entityKind"]) {
3879
- if (scope[field] !== undefined && typeof scope[field] !== "string")
3880
- issues.push(`${prefix}.scope.${field} must be a string`);
3881
- }
3882
- }
3883
- if (typeof target.path !== "string" || !isRepoRelativePosixPath(target.path))
3884
- issues.push(`${prefix}.path must be a repository-relative POSIX path`);
3885
- if (typeof target.ownership !== "string" || !Object.hasOwn(OWNERSHIPS, target.ownership))
3886
- issues.push(`${prefix}.ownership is unsupported`);
3887
- if (typeof target.format !== "string" || !Object.hasOwn(FORMATS, target.format))
3888
- issues.push(`${prefix}.format is unsupported`);
3889
- if (!isDigest(target.outputDigest))
3890
- issues.push(`${prefix}.outputDigest must be a SHA-256 digest`);
3891
- if (target.sourceStamps !== undefined && target.type !== "entity-summary" && !isRuntimeTopologyTargetType(target.type)) {
3892
- issues.push(`${prefix}.sourceStamps are only allowed on entity-summary and runtime topology targets`);
3893
- }
3894
- if (target.scale !== undefined && target.type !== "entity-summary")
3895
- issues.push(`${prefix}.scale is only allowed on entity-summary targets`);
3896
- if (target.sourceStamps !== undefined) {
3897
- const stamps = record3(target.sourceStamps);
3898
- if (!stamps || Object.keys(stamps).length === 0)
3899
- issues.push(`${prefix}.sourceStamps must be a non-empty object keyed by node id`);
3900
- else {
3901
- for (const [nodeId, digest] of Object.entries(stamps)) {
3902
- if (!isNonEmptyString(nodeId))
3903
- issues.push(`${prefix}.sourceStamps keys must be non-empty node ids`);
3904
- if (!isDigest(digest))
3905
- issues.push(`${prefix}.sourceStamps.${nodeId} must be a SHA-256 digest`);
3906
- }
3907
- }
3908
- }
3909
- const ownNodeId = scope?.id;
3910
- const stampsOwnNode = typeof ownNodeId === "string" && record3(target.sourceStamps) !== undefined && Object.hasOwn(record3(target.sourceStamps), ownNodeId);
3911
- if (stampsOwnNode !== (target.scale !== undefined))
3912
- issues.push(`${prefix}.scale must be present exactly when sourceStamps stamps the target's own node`);
3913
- if (target.scale !== undefined) {
3914
- const scale = record3(target.scale);
3915
- if (!scale)
3916
- issues.push(`${prefix}.scale must be an object`);
3917
- else {
3918
- issues.push(...exactKeys(scale, ["fileCountBucket", "lineCountBucket"], [], `${prefix}.scale`));
3919
- for (const field of ["fileCountBucket", "lineCountBucket"]) {
3920
- if (!isArchitectureScaleBucket(scale[field]))
3921
- issues.push(`${prefix}.scale.${field} must be a 1-2-5 magnitude bucket`);
3922
- }
3923
- }
3924
- }
3925
- return issues;
3926
- }
3927
- function record3(value) {
3928
- return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
3929
- }
3930
- function exactKeys(value, required, optional, prefix) {
3931
- const issues = required.filter((key) => !(key in value)).map((key) => `${prefix}.${key} is required`);
3932
- const allowed = new Set([...required, ...optional]);
3933
- for (const key of Object.keys(value))
3934
- if (!allowed.has(key))
3935
- issues.push(`${prefix}.${key} is not allowed`);
3936
- return issues;
3937
- }
3938
- function isDigest(value) {
3939
- return typeof value === "string" && SHA256.test(value);
3940
- }
3941
- function isNonEmptyString(value) {
3942
- return typeof value === "string" && value.trim() !== "";
3943
- }
3944
- function isSortedUniqueStrings(values) {
3945
- return values.every((value, index) => typeof value === "string" && (index === 0 || values[index - 1] < value));
3946
- }
3947
- function compareStrings(left, right) {
3948
- return left < right ? -1 : left > right ? 1 : 0;
3949
- }
3950
- function versionNumber(value, family) {
3951
- if (typeof value !== "string" || !value.startsWith(family))
3952
- return;
3953
- const suffix = value.slice(family.length);
3954
- if (!/^[1-9][0-9]*$/.test(suffix))
3955
- return;
3956
- const version = Number(suffix);
3957
- return Number.isSafeInteger(version) ? version : undefined;
3958
- }
3959
- function architectureDocsProjectionCompatibilityIssues(value, engine = {
3960
- rendererVersion: ARCHITECTURE_DOCS_RENDERER_VERSION,
3961
- protocolVersion: PROJECTION_REQUEST_SCHEMA_VERSION
3962
- }) {
3963
- const manifest = record3(value);
3964
- if (!manifest)
3965
- return [];
3966
- const issues = [];
3967
- if (["minimumRendererVersion", "minimumProtocolVersion"].some((key) => Object.hasOwn(manifest, key)) && manifest.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION)
3968
- issues.push("projection manifest floors require the current schema");
3969
- if (typeof manifest.schemaVersion === "string" && manifest.schemaVersion !== ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION && !isSupersededArchitectureDocsProjectionManifestSchemaVersion(manifest.schemaVersion))
3970
- issues.push("projection manifest schema is unsupported by this engine");
3971
- for (const [key, family, current] of [
3972
- ["minimumRendererVersion", "archcontext.docs-renderer/v", engine.rendererVersion],
3973
- ["minimumProtocolVersion", "archcontext.projection-request/v", engine.protocolVersion]
3974
- ]) {
3975
- if (!Object.hasOwn(manifest, key))
3976
- continue;
3977
- const required = versionNumber(manifest[key], family);
3978
- const supported = versionNumber(current, family);
3979
- if (required === undefined || supported === undefined || supported < required)
3980
- issues.push(`projection manifest ${key} is unsupported by this engine`);
3981
- }
3982
- return issues;
3983
- }
3984
- var ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION = "archcontext.architecture-docs-projection-manifest/v3", SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS, PROJECTION_MANIFEST_UPGRADE_REQUIRED = "projection-manifest-upgrade-required", PROJECTION_MANIFEST_INVALID = "projection-manifest-invalid", PROJECTION_FOOTPRINT_UNCOVERED = "projection-footprint-uncovered", ARCHITECTURE_DOCS_PROJECTION_PROVENANCE_SCHEMA_VERSION = "archcontext.architecture-docs-projection-provenance/v3", ARCHITECTURE_DOCS_LAYOUT_VERSION_V1 = "archcontext.docs-layout/v1", ARCHITECTURE_SEMANTIC_STATE_SCHEMA_VERSION = "archcontext.architecture-semantic-state/v1", ARCHITECTURE_DOCS_PROJECTION_PROFILES, SHA256, TARGET_TYPES, RUNTIME_TOPOLOGY_TARGET_TYPES, SCOPE_KINDS, OWNERSHIPS, FORMATS;
3985
- var init_projection_manifest = __esm(() => {
3986
- init_projection();
3987
- init_schema();
3988
- SUPERSEDED_ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSIONS = [
3989
- "archcontext.architecture-docs-projection-manifest/v1",
3990
- "archcontext.architecture-docs-projection-manifest/v2"
3991
- ];
3992
- ARCHITECTURE_DOCS_PROJECTION_PROFILES = ["default", "repo-harness/v1"];
3993
- SHA256 = /^sha256:[a-f0-9]{64}$/;
3994
- TARGET_TYPES = {
3995
- "architecture-index": true,
3996
- "entity-summary": true,
3997
- "relation-summary": true,
3998
- "decision-index": true,
3999
- "architecture-changelog": true,
4000
- "diagram-mermaid": true,
4001
- "diagram-structurizr": true,
4002
- "diagram-likec4": true,
4003
- "diagram-runtime-topology": true,
4004
- "runtime-topology-summary": true,
4005
- "agent-context": true
4006
- };
4007
- RUNTIME_TOPOLOGY_TARGET_TYPES = ["diagram-runtime-topology", "runtime-topology-summary"];
4008
- SCOPE_KINDS = { repository: true, entity: true, relation: true, decision: true, diagram: true, changelog: true };
4009
- OWNERSHIPS = { generated: true, mixed: true };
4010
- FORMATS = { markdown: true, mermaid: true, "structurizr-json": true, likec4: true };
4011
- });
4012
-
4013
4019
  // packages/contracts/src/product-version.ts
4014
4020
  function productVersionManifest() {
4015
4021
  return {
@@ -4095,7 +4101,7 @@ function compareVersionTriples(left, right) {
4095
4101
  }
4096
4102
  return 0;
4097
4103
  }
4098
- var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.9.4", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v2", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
4104
+ var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.10.0", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v2", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
4099
4105
 
4100
4106
  // packages/contracts/src/refactor.ts
4101
4107
  function refactorNamespaceIssues(value, label = "product.id") {
@@ -18071,12 +18077,13 @@ function resolveArchitectureDocumentationLayout(input) {
18071
18077
  });
18072
18078
  const relationTargets = (profile === REPO_HARNESS_PROJECTION_PROFILE ? [] : input.relations).map((relation) => layoutTarget(`projection_target.relation.${stableId(relation.id)}`, "relation-summary", { kind: "relation", id: relation.id }, `docs/architecture/relations/${pathSegment(relation.id)}.md`, "mixed", "markdown"));
18073
18079
  const topologyTargets = hasRuntimeTopologyNodes(input.nodes) ? RUNTIME_TOPOLOGY_TARGETS : [];
18074
- const targets = [FIXED_TARGETS[0], ...entityTargets, ...relationTargets, ...FIXED_TARGETS.slice(1), ...topologyTargets].map((target) => ({ ...target, path: requiredPath(target.path, target.targetId) }));
18080
+ const targets = (profile === REPO_HARNESS_PROJECTION_PROFILE ? [...entityTargets, ...topologyTargets] : [FIXED_TARGETS[0], ...entityTargets, ...relationTargets, ...FIXED_TARGETS.slice(1), ...topologyTargets]).map((target) => ({ ...target, path: requiredPath(target.path, target.targetId) }));
18075
18081
  assertUniqueTargets(targets);
18076
18082
  return {
18077
18083
  profile,
18078
18084
  targets,
18079
18085
  expectedPaths: [...new Set([...targets.map((target) => target.path), "docs/architecture/.projection-manifest.json"])].sort(),
18086
+ retiredTargetPaths: profile === REPO_HARNESS_PROJECTION_PROFILE ? FIXED_TARGETS.map((target) => target.path) : [],
18080
18087
  orphanRoots: ["docs/architecture/modules", "docs/architecture/relations"],
18081
18088
  entityPathByNodeId: new Map(entityTargets.map((target, index) => [targetNodes[index].id, target.path]))
18082
18089
  };
@@ -18124,7 +18131,10 @@ function loadArchitectureFilesForLayout(root, layout) {
18124
18131
  }
18125
18132
  if (paths.has(ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH)) {
18126
18133
  const manifest = readProjectionOwnedFile(resolve5(root, ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH), ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH);
18127
- for (const output of committedGeneratedOutputs(currentFormatManifest(manifest.body))) {
18134
+ const retired = new Set(layout.retiredTargetPaths);
18135
+ for (const output of committedProjectionOutputs(currentFormatManifest(manifest.body))) {
18136
+ if (output.ownership !== "generated" && !retired.has(output.path))
18137
+ continue;
18128
18138
  if (resolveSafeRegularPath(root, output.path, false))
18129
18139
  paths.add(output.path);
18130
18140
  }
@@ -18132,17 +18142,20 @@ function loadArchitectureFilesForLayout(root, layout) {
18132
18142
  return [...paths].sort().map((path) => readProjectionOwnedFile(resolve5(root, path), path));
18133
18143
  }
18134
18144
  var OUTPUT_DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;
18135
- function committedGeneratedOutputs(manifest) {
18145
+ function committedProjectionOutputs(manifest) {
18136
18146
  if (manifest === undefined)
18137
18147
  return [];
18138
18148
  const outputs = [];
18139
18149
  for (const [targetId, row] of Object.entries(manifest.targets)) {
18140
- if (row.ownership !== "generated" || !OUTPUT_DIGEST_PATTERN.test(row.outputDigest) || !isRepoRelativePosixPath(row.path) || !row.path.startsWith("docs/architecture/") || row.path === ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH)
18150
+ if (!OUTPUT_DIGEST_PATTERN.test(row.outputDigest) || !isRepoRelativePosixPath(row.path) || !row.path.startsWith("docs/architecture/") || row.path === ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH)
18141
18151
  continue;
18142
- outputs.push({ targetId, path: row.path, outputDigest: row.outputDigest });
18152
+ outputs.push({ targetId, path: row.path, ownership: row.ownership, outputDigest: row.outputDigest });
18143
18153
  }
18144
18154
  return outputs;
18145
18155
  }
18156
+ function committedGeneratedOutputs(manifest) {
18157
+ return committedProjectionOutputs(manifest).filter((output) => output.ownership === "generated").map(({ targetId, path, outputDigest }) => ({ targetId, path, outputDigest }));
18158
+ }
18146
18159
  function currentFormatManifest(body) {
18147
18160
  let parsed;
18148
18161
  try {
@@ -20034,9 +20047,17 @@ class ProjectionPreconditionError extends Error {
20034
20047
  class ProjectionManifestUpgradeRequiredError extends ProjectionPreconditionError {
20035
20048
  schemaVersion;
20036
20049
  reasonCode = PROJECTION_MANIFEST_UPGRADE_REQUIRED;
20050
+ details;
20037
20051
  constructor(schemaVersion) {
20038
- super(`${PROJECTION_MANIFEST_UPGRADE_REQUIRED}: ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH} is ${schemaVersion}, and this archctx reads only ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION}; reach a clean projection on the earlier release first, then re-baseline once with archctx docs apply --approved --profile <default|repo-harness/v1>; if that apply names whole-file outputs the earlier release wrote, remove them with git rm and run it again`);
20052
+ super(`${PROJECTION_MANIFEST_UPGRADE_REQUIRED}: ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH} is ${schemaVersion}, and this archctx reads only ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION}; reach a clean projection on the earlier release first, then re-baseline once with ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_UPGRADE_COMMAND}; if that apply names whole-file outputs the earlier release wrote, remove them with git rm and run it again; ${ARCHITECTURE_DOCS_PROJECTION_MANIFEST_MIGRATION_GUIDE} lists the model and release preconditions`);
20039
20053
  this.schemaVersion = schemaVersion;
20054
+ this.details = isSupersededArchitectureDocsProjectionManifestSchemaVersion(schemaVersion) ? {
20055
+ manifestPath: ARCHITECTURE_DOCS_PROJECTION_MANIFEST_PATH,
20056
+ foundSchemaVersion: schemaVersion,
20057
+ supportedSchemaVersion: ARCHITECTURE_DOCS_PROJECTION_MANIFEST_SCHEMA_VERSION,
20058
+ upgradeCommand: ARCHITECTURE_DOCS_PROJECTION_MANIFEST_UPGRADE_COMMAND,
20059
+ migrationGuide: ARCHITECTURE_DOCS_PROJECTION_MANIFEST_MIGRATION_GUIDE
20060
+ } : {};
20040
20061
  }
20041
20062
  }
20042
20063
 
@@ -25459,6 +25480,8 @@ function architectureDeltaTask(git) {
25459
25480
  var CODEGRAPH_IMPORT_NODE_READ_LIMIT = 50000;
25460
25481
  var CODEGRAPH_IMPORT_NODE_OUTPUT_BYTES = 4 * 1024;
25461
25482
  function prepareArchitectureDocumentationProjectionSnapshot(root, model, options = {}) {
25483
+ if (codeGraphIndexAvailable(root))
25484
+ assertRepositoryCodeFactsReady(root, options.binary ? { binary: options.binary } : {});
25462
25485
  const baseHeadSha = readProjectionHeadSha(root);
25463
25486
  const sourceFiles = listGitVisibleFiles(root);
25464
25487
  const worktreeDigest = architectureDocumentationProjectionWorktreeDigest(root, model, sourceFiles);
@@ -25603,7 +25626,33 @@ function prepareProjectionCodeFacts(root, model, options) {
25603
25626
  }
25604
25627
  };
25605
25628
  }
25629
+
25630
+ class CodeGraphIndexBuildInProgressError extends Error {
25631
+ constructor() {
25632
+ super("CodeGraph index build is in progress");
25633
+ this.name = "CodeGraphIndexBuildInProgressError";
25634
+ }
25635
+ }
25636
+ function codeGraphIndexBuildInProgress(workspaceRoot) {
25637
+ let raw;
25638
+ try {
25639
+ raw = readFileSync7(join3(workspaceRoot, ".codegraph", "codegraph.lock"), "utf8").trim();
25640
+ } catch {
25641
+ return false;
25642
+ }
25643
+ const pid = Number.parseInt(raw, 10);
25644
+ if (!Number.isSafeInteger(pid) || pid <= 0 || String(pid) !== raw)
25645
+ return false;
25646
+ try {
25647
+ process.kill(pid, 0);
25648
+ return true;
25649
+ } catch (error) {
25650
+ return error.code === "EPERM";
25651
+ }
25652
+ }
25606
25653
  function readProjectionCodeGraphStatus(invocation, root, timeout, envOverrides) {
25654
+ if (codeGraphIndexBuildInProgress(root))
25655
+ throw new CodeGraphIndexBuildInProgressError;
25607
25656
  const output = runProjectionCodeGraph(invocation, root, ["status", "-j", root], timeout, envOverrides);
25608
25657
  try {
25609
25658
  return JSON.parse(output);
@@ -25922,8 +25971,9 @@ function mirrorCodeGraphInputs(root, gitDir, commonDir, destination) {
25922
25971
  var CODEGRAPH_NO_DOWNLOAD_ENV = { CODEGRAPH_NO_DOWNLOAD: "1" };
25923
25972
  function inspectRepositoryCodeFacts(root, options = {}) {
25924
25973
  const schemaVersion = "archcontext.repository-code-facts/v1";
25925
- let codeGraphVersion;
25974
+ let codeGraphVersion = "";
25926
25975
  let status;
25976
+ let indexBuildInProgress = false;
25927
25977
  const indexPresent = codeGraphIndexAvailable(root);
25928
25978
  try {
25929
25979
  const invocation = options.binary ? codeGraphCliInvocation(options.binary, root, "") : packagedCodeGraphCliInvocation();
@@ -25931,18 +25981,37 @@ function inspectRepositoryCodeFacts(root, options = {}) {
25931
25981
  if (indexPresent)
25932
25982
  status = readProjectionCodeGraphStatus(invocation, root, options.timeouts?.statusMs ?? 1e4, CODEGRAPH_NO_DOWNLOAD_ENV);
25933
25983
  } catch (error) {
25934
- return {
25935
- schemaVersion,
25936
- state: "unavailable",
25937
- requiredVersion: REQUIRED_CODEGRAPH_VERSION,
25938
- reasonCode: "codegraph-unavailable",
25939
- message: (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim().slice(0, 400)
25940
- };
25984
+ if (!(error instanceof CodeGraphIndexBuildInProgressError)) {
25985
+ return {
25986
+ schemaVersion,
25987
+ state: "unavailable",
25988
+ requiredVersion: REQUIRED_CODEGRAPH_VERSION,
25989
+ reasonCode: "codegraph-unavailable",
25990
+ message: (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim().slice(0, 400)
25991
+ };
25992
+ }
25993
+ indexBuildInProgress = true;
25941
25994
  }
25942
25995
  const versionIssues = codeGraphVersion === REQUIRED_CODEGRAPH_VERSION ? [] : [{ code: "version-mismatch", message: CODE_FACTS_ISSUE_MESSAGES["version-mismatch"] }];
25943
25996
  if (!indexPresent) {
25944
25997
  return { schemaVersion, state: "index-missing", indexPresent: false, requiredVersion: REQUIRED_CODEGRAPH_VERSION, codeGraphVersion, issues: versionIssues };
25945
25998
  }
25999
+ if (indexBuildInProgress) {
26000
+ return {
26001
+ schemaVersion,
26002
+ state: "not-ready",
26003
+ indexPresent: true,
26004
+ requiredVersion: REQUIRED_CODEGRAPH_VERSION,
26005
+ codeGraphVersion,
26006
+ indexBuiltWithVersion: null,
26007
+ extractionVersion: { builtWith: null, current: null },
26008
+ indexState: null,
26009
+ reindexRecommended: null,
26010
+ pendingRefs: null,
26011
+ pendingChanges: null,
26012
+ issues: [...versionIssues, { code: "index-incomplete", message: CODE_FACTS_ISSUE_MESSAGES["index-incomplete"] }]
26013
+ };
26014
+ }
25946
26015
  if (typeof status !== "object" || status === null || Array.isArray(status)) {
25947
26016
  return {
25948
26017
  schemaVersion,
@@ -26329,6 +26398,8 @@ function selectedProducerFailure(error, stage) {
26329
26398
  const details = stage === "docs-anchors" || stage === "flows-check" ? {} : { checks: ["ownership", "anchors"] };
26330
26399
  return new FailureError(selectedProducerData(error, "code"), selectedProducerData(error, "reasonCode"), details);
26331
26400
  }
26401
+ if (error instanceof ProjectionManifestUpgradeRequiredError)
26402
+ return new FailureError("AC_PRECONDITION_FAILED", selectedProducerData(error, "reasonCode"), selectedProducerData(error, "details"));
26332
26403
  if (error instanceof ProjectionPreconditionError)
26333
26404
  return new FailureError("AC_PRECONDITION_FAILED", selectedProducerData(error, "reasonCode"));
26334
26405
  if (error instanceof ProjectionCodeFactsUnavailableError)
@@ -34030,6 +34101,8 @@ function publicOperationFailure(error) {
34030
34101
  failure = toEnvelope("public.operation", undefined, "public-operation").error;
34031
34102
  } else if (error instanceof GitVisibleFilesUnavailableError)
34032
34103
  failure = knownFailure(own2(error, "code"), own2(error, "reasonCode"));
34104
+ else if (error instanceof ProjectionManifestUpgradeRequiredError)
34105
+ failure = knownFailure("AC_PRECONDITION_FAILED", own2(error, "reasonCode"), own2(error, "details"));
34033
34106
  else if (error instanceof ProjectionPreconditionError)
34034
34107
  failure = knownFailure("AC_PRECONDITION_FAILED", own2(error, "reasonCode"));
34035
34108
  else if (error instanceof ProjectionCodeFactsUnavailableError)
@@ -41603,7 +41676,7 @@ function rpcRequiredBoolean(params, index, context, label) {
41603
41676
  function rpcOptionalString(params, index, context, label) {
41604
41677
  const value = params[index];
41605
41678
  if (value === undefined || value === null)
41606
- return value;
41679
+ return;
41607
41680
  if (typeof value !== "string")
41608
41681
  throw rpcInputInvalid(context, `${label} must be a string`);
41609
41682
  return value;
@@ -41611,7 +41684,7 @@ function rpcOptionalString(params, index, context, label) {
41611
41684
  function rpcOptionalNumber(params, index, context, label) {
41612
41685
  const value = params[index];
41613
41686
  if (value === undefined || value === null)
41614
- return value;
41687
+ return;
41615
41688
  if (typeof value !== "number" || !Number.isFinite(value))
41616
41689
  throw rpcInputInvalid(context, `${label} must be a number`);
41617
41690
  return value;
@@ -41619,7 +41692,7 @@ function rpcOptionalNumber(params, index, context, label) {
41619
41692
  function rpcOptionalStringArray(params, index, context, label) {
41620
41693
  const value = params[index];
41621
41694
  if (value === undefined || value === null)
41622
- return value;
41695
+ return;
41623
41696
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string"))
41624
41697
  throw rpcInputInvalid(context, `${label} must be an array of strings`);
41625
41698
  return value;
@@ -41636,7 +41709,7 @@ function rpcRequiredObject(params, index, context, label) {
41636
41709
  function rpcOptionalObject(params, index, context, label) {
41637
41710
  const value = params[index];
41638
41711
  if (value === undefined || value === null)
41639
- return value;
41712
+ return;
41640
41713
  if (!isPlainRpcObject(value))
41641
41714
  throw rpcInputInvalid(context, `${label} must be an object`);
41642
41715
  return value;
@@ -61940,7 +62013,32 @@ function readFilePrefix2(path, length) {
61940
62013
  }
61941
62014
  }
61942
62015
  var CODEGRAPH_IMPORT_NODE_OUTPUT_BYTES2 = 4 * 1024;
62016
+ class CodeGraphIndexBuildInProgressError2 extends Error {
62017
+ constructor() {
62018
+ super("CodeGraph index build is in progress");
62019
+ this.name = "CodeGraphIndexBuildInProgressError";
62020
+ }
62021
+ }
62022
+ function codeGraphIndexBuildInProgress2(workspaceRoot) {
62023
+ let raw;
62024
+ try {
62025
+ raw = readFileSync32(join26(workspaceRoot, ".codegraph", "codegraph.lock"), "utf8").trim();
62026
+ } catch {
62027
+ return false;
62028
+ }
62029
+ const pid = Number.parseInt(raw, 10);
62030
+ if (!Number.isSafeInteger(pid) || pid <= 0 || String(pid) !== raw)
62031
+ return false;
62032
+ try {
62033
+ process.kill(pid, 0);
62034
+ return true;
62035
+ } catch (error) {
62036
+ return error.code === "EPERM";
62037
+ }
62038
+ }
61943
62039
  function readProjectionCodeGraphStatus2(invocation, root, timeout, envOverrides) {
62040
+ if (codeGraphIndexBuildInProgress2(root))
62041
+ throw new CodeGraphIndexBuildInProgressError2;
61944
62042
  const output = runProjectionCodeGraph2(invocation, root, ["status", "-j", root], timeout, envOverrides);
61945
62043
  try {
61946
62044
  return JSON.parse(output);
@@ -62011,8 +62109,9 @@ var CODEGRAPH_SNAPSHOT_MAX_BYTES2 = 512 * 1024 * 1024;
62011
62109
  var CODEGRAPH_NO_DOWNLOAD_ENV2 = { CODEGRAPH_NO_DOWNLOAD: "1" };
62012
62110
  function inspectRepositoryCodeFacts2(root, options = {}) {
62013
62111
  const schemaVersion = "archcontext.repository-code-facts/v1";
62014
- let codeGraphVersion;
62112
+ let codeGraphVersion = "";
62015
62113
  let status;
62114
+ let indexBuildInProgress = false;
62016
62115
  const indexPresent = codeGraphIndexAvailable2(root);
62017
62116
  try {
62018
62117
  const invocation = options.binary ? codeGraphCliInvocation2(options.binary, root, "") : packagedCodeGraphCliInvocation2();
@@ -62020,18 +62119,37 @@ function inspectRepositoryCodeFacts2(root, options = {}) {
62020
62119
  if (indexPresent)
62021
62120
  status = readProjectionCodeGraphStatus2(invocation, root, options.timeouts?.statusMs ?? 1e4, CODEGRAPH_NO_DOWNLOAD_ENV2);
62022
62121
  } catch (error) {
62023
- return {
62024
- schemaVersion,
62025
- state: "unavailable",
62026
- requiredVersion: REQUIRED_CODEGRAPH_VERSION2,
62027
- reasonCode: "codegraph-unavailable",
62028
- message: (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim().slice(0, 400)
62029
- };
62122
+ if (!(error instanceof CodeGraphIndexBuildInProgressError2)) {
62123
+ return {
62124
+ schemaVersion,
62125
+ state: "unavailable",
62126
+ requiredVersion: REQUIRED_CODEGRAPH_VERSION2,
62127
+ reasonCode: "codegraph-unavailable",
62128
+ message: (error instanceof Error ? error.message : String(error)).replace(/\s+/g, " ").trim().slice(0, 400)
62129
+ };
62130
+ }
62131
+ indexBuildInProgress = true;
62030
62132
  }
62031
62133
  const versionIssues = codeGraphVersion === REQUIRED_CODEGRAPH_VERSION2 ? [] : [{ code: "version-mismatch", message: CODE_FACTS_ISSUE_MESSAGES["version-mismatch"] }];
62032
62134
  if (!indexPresent) {
62033
62135
  return { schemaVersion, state: "index-missing", indexPresent: false, requiredVersion: REQUIRED_CODEGRAPH_VERSION2, codeGraphVersion, issues: versionIssues };
62034
62136
  }
62137
+ if (indexBuildInProgress) {
62138
+ return {
62139
+ schemaVersion,
62140
+ state: "not-ready",
62141
+ indexPresent: true,
62142
+ requiredVersion: REQUIRED_CODEGRAPH_VERSION2,
62143
+ codeGraphVersion,
62144
+ indexBuiltWithVersion: null,
62145
+ extractionVersion: { builtWith: null, current: null },
62146
+ indexState: null,
62147
+ reindexRecommended: null,
62148
+ pendingRefs: null,
62149
+ pendingChanges: null,
62150
+ issues: [...versionIssues, { code: "index-incomplete", message: CODE_FACTS_ISSUE_MESSAGES["index-incomplete"] }]
62151
+ };
62152
+ }
62035
62153
  if (typeof status !== "object" || status === null || Array.isArray(status)) {
62036
62154
  return {
62037
62155
  schemaVersion,