Build workspace agent, capability graph, and versioned cutovers

This commit is contained in:
2026-09-05 12:33:52 -07:00
parent c4d42a0ac5
commit ce793cc54f
55 changed files with 5600 additions and 2529 deletions
+75 -20
View File
@@ -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);