Build workspace agent, capability graph, and versioned cutovers
This commit is contained in:
@@ -61,7 +61,7 @@ export type CapabilityValidationIssueCode =
|
||||
| "invalid-dependency-binding"
|
||||
| "private-attachment-access"
|
||||
| "incompatible-package-receiver"
|
||||
| "unsatisfied-receiver-interface"
|
||||
| "unsatisfied-interface"
|
||||
| "cyclic-conformance-requirement"
|
||||
| "missing-operation-binding"
|
||||
| "unknown-operation-binding"
|
||||
@@ -917,7 +917,7 @@ const validatePackages = (
|
||||
validateConstraint(issues, port.requirement.target, `${portPath}.requirement.target`, indexes);
|
||||
uniquePrimitiveList(issues, port.requirement.primitives, `${portPath}.requirement.primitives`);
|
||||
break;
|
||||
case "receiver-interface":
|
||||
case "interface":
|
||||
if (!indexes.interfaces.has(port.requirement.interfaceRevisionId)) {
|
||||
issue(
|
||||
issues,
|
||||
@@ -976,6 +976,7 @@ const validateTraversal = (
|
||||
atomId: AtomId,
|
||||
traversal: { edgeTypeId: EdgeTypeId; projectionId: EdgeProjectionId },
|
||||
path: string,
|
||||
conformance?: Pick<Conformance, "atomId" | "interfaceRevisionId">,
|
||||
) => {
|
||||
const attachment = findAttachment(indexes, "edge", traversal.edgeTypeId);
|
||||
if (!attachment || attachment.attachment.kind !== "edge") {
|
||||
@@ -987,6 +988,7 @@ const validateTraversal = (
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
validateAttachmentAccess(issues, attachment, conformance, `${path}.edgeTypeId`);
|
||||
const projection = edgeProjection(attachment.attachment, traversal.projectionId);
|
||||
if (!projection) {
|
||||
issue(
|
||||
@@ -1085,6 +1087,7 @@ const validateBoundDependencies = (
|
||||
params.atomId,
|
||||
stateBinding.via,
|
||||
`${path}.binding.via`,
|
||||
params.conformance,
|
||||
)
|
||||
: undefined;
|
||||
if (
|
||||
@@ -1145,6 +1148,7 @@ const validateBoundDependencies = (
|
||||
params.atomId,
|
||||
edgeBinding.via,
|
||||
`${path}.binding.via`,
|
||||
params.conformance,
|
||||
)
|
||||
: undefined;
|
||||
const originMatches = edgeBinding.via
|
||||
@@ -1189,10 +1193,10 @@ const validateBoundDependencies = (
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "receiver-interface": {
|
||||
case "interface": {
|
||||
const interfaceBinding = binding as Extract<
|
||||
DependencyBinding,
|
||||
{ kind: "receiver-interface" }
|
||||
{ kind: "interface" }
|
||||
>;
|
||||
if (interfaceBinding.interfaceRevisionId !== requirement.interfaceRevisionId) {
|
||||
issue(
|
||||
@@ -1203,16 +1207,38 @@ const validateBoundDependencies = (
|
||||
);
|
||||
break;
|
||||
}
|
||||
const targetKey = conformanceKey(params.atomId, requirement.interfaceRevisionId);
|
||||
if (!params.indexes.conformances.has(targetKey)) {
|
||||
issue(
|
||||
issues,
|
||||
"unsatisfied-receiver-interface",
|
||||
`${path}.binding.interfaceRevisionId`,
|
||||
`Receiver atom ${params.atomId} does not conform to ${requirement.interfaceRevisionId}`,
|
||||
);
|
||||
} else if (params.graphSourceKey) {
|
||||
params.requirementGraph.get(params.graphSourceKey)?.add(targetKey);
|
||||
const traversal = interfaceBinding.via
|
||||
? validateTraversal(
|
||||
issues,
|
||||
params.indexes,
|
||||
params.atomId,
|
||||
interfaceBinding.via,
|
||||
`${path}.binding.via`,
|
||||
params.conformance,
|
||||
)
|
||||
: undefined;
|
||||
const candidateAtoms = interfaceBinding.via
|
||||
? traversal
|
||||
? [...params.indexes.atoms.keys()].filter((atomId) =>
|
||||
atomSatisfiesConstraint(
|
||||
atomId as AtomId,
|
||||
traversal.target.constraint,
|
||||
params.indexes.conformances,
|
||||
)) as AtomId[]
|
||||
: []
|
||||
: [params.atomId];
|
||||
for (const atomId of candidateAtoms) {
|
||||
const targetKey = conformanceKey(atomId, requirement.interfaceRevisionId);
|
||||
if (!params.indexes.conformances.has(targetKey)) {
|
||||
issue(
|
||||
issues,
|
||||
"unsatisfied-interface",
|
||||
`${path}.binding.interfaceRevisionId`,
|
||||
`${interfaceBinding.via ? "Related" : "Receiver"} atom ${atomId} does not conform to ${requirement.interfaceRevisionId}`,
|
||||
);
|
||||
} else if (params.graphSourceKey) {
|
||||
params.requirementGraph.get(params.graphSourceKey)?.add(targetKey);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1276,7 +1302,7 @@ const validatePackageReceiver = (
|
||||
if (!params.indexes.conformances.has(targetKey)) {
|
||||
issue(
|
||||
issues,
|
||||
"unsatisfied-receiver-interface",
|
||||
"unsatisfied-interface",
|
||||
params.path,
|
||||
`Atom ${params.atomId} does not conform to ${requiredInterface}`,
|
||||
);
|
||||
@@ -1971,6 +1997,9 @@ export const computeCapabilityClosure = (
|
||||
const constructors = new Set<AtomId>();
|
||||
const queued = [...roots];
|
||||
const visited = new Set<string>();
|
||||
const sourceConformances = new Map(
|
||||
[...plan.conformances].map(([key, value]) => [key, value.source]),
|
||||
);
|
||||
|
||||
const includeDependencies = (
|
||||
atomId: AtomId,
|
||||
@@ -1990,12 +2019,38 @@ export const computeCapabilityClosure = (
|
||||
attachments.add(dependency.binding.via.edgeTypeId);
|
||||
}
|
||||
break;
|
||||
case "receiver-interface":
|
||||
queued.push({
|
||||
atomId,
|
||||
interfaceRevisionId: dependency.binding.interfaceRevisionId,
|
||||
});
|
||||
case "interface": {
|
||||
if (dependency.binding.via) {
|
||||
attachments.add(dependency.binding.via.edgeTypeId);
|
||||
}
|
||||
const targetAtoms = dependency.binding.via
|
||||
? (() => {
|
||||
const attachment = plan.attachments.get(
|
||||
`edge\u0000${dependency.binding.via!.edgeTypeId}`,
|
||||
)?.attachment;
|
||||
if (!attachment || attachment.kind !== "edge") return [];
|
||||
const projection = edgeProjection(
|
||||
attachment,
|
||||
dependency.binding.via!.projectionId,
|
||||
);
|
||||
return projection
|
||||
? [...plan.atoms.keys()].filter((candidate) =>
|
||||
atomSatisfiesConstraint(
|
||||
candidate,
|
||||
projection.target.constraint,
|
||||
sourceConformances,
|
||||
))
|
||||
: [];
|
||||
})()
|
||||
: [atomId];
|
||||
for (const targetAtom of targetAtoms) {
|
||||
queued.push({
|
||||
atomId: targetAtom,
|
||||
interfaceRevisionId: dependency.binding.interfaceRevisionId,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "constructor": {
|
||||
constructors.add(dependency.binding.atomId);
|
||||
const constructor = plan.constructors.get(dependency.binding.atomId);
|
||||
|
||||
Reference in New Issue
Block a user