The product was materialized from the template at `4dc033c` and has stayed on it through 43 template commits, so it was missing all three rounds of adapter remediation — including files it never had, such as the shared `abortable-operation` primitive and the `exact-snapshot` decoder that later fixes are written against. Taking only the newest round was not possible for that reason: the delta is coherent only as a whole. The product had not touched `src/adapters` at all since materialization, so the 140-file delta applied with a three-way merge and no conflicts. `package.json` was the single overlap and merged cleanly: the product owns `name`, the template contributed `check:adapter-inventory`, `check:remediation-ledger` and the image-resolve-signal type fixture. All 24 product-owned files — README, index.html, CI workflow, i18n catalog, home page, generated schemas, evidence scripts, component and visual snapshots — are byte-identical to `main`. `template.lock.json` now pins the synced revision and tree. Verified in this repository, not inherited from the template: six type projects, lint, nine gates (adapter inventory, remediation ledger, registries, diagnostics, realtime boundaries, architecture, browser file/storage boundaries, optional recipes, documentation), the production build, and 2,054 of 2,073 tests. The 19 failures are all in `tests/unit/ci-artifact-contract.test.ts` and are the same pre-existing sandbox RLIMIT, EMFILE, umask and `/tmp` permission behaviour the template records; four suites that failed once under parallel load pass in isolation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
144 lines
3.9 KiB
TypeScript
144 lines
3.9 KiB
TypeScript
import type {
|
|
CommandEffectDescriptor,
|
|
CommandEffectClassification,
|
|
} from "../../contracts/external-contract-runtime.ts";
|
|
|
|
/**
|
|
* §8.7–§8.9. Mutation effect certainty.
|
|
*
|
|
* The frontend never infers "not applied" from an HTTP status alone. Anything
|
|
* observed after the request was dispatched but before a classified terminal
|
|
* response is `MAYBE_APPLIED`, which forbids automatic resend.
|
|
*/
|
|
|
|
export type MutationEffectCertainty =
|
|
| "NOT_STARTED"
|
|
| "NOT_APPLIED"
|
|
| "MAYBE_APPLIED"
|
|
| "APPLIED_CONFIRMED";
|
|
|
|
export type PhysicalAttemptState =
|
|
| "NOT_STARTED"
|
|
| "PREPARING"
|
|
| "READY_TO_SEND"
|
|
| "DISPATCHED"
|
|
| "RESPONSE_HEADERS"
|
|
| "READING_BODY"
|
|
| "VALIDATING"
|
|
| "MAPPING_READY"
|
|
| "SETTLED";
|
|
|
|
/**
|
|
* `READY_TO_SEND` is recorded immediately before entering the `fetch()`
|
|
* invocation expression and `DISPATCHED` immediately after the promise is
|
|
* returned. A synchronous throw therefore leaves the attempt `NOT_STARTED`.
|
|
*/
|
|
export function certaintyForAbandonedAttempt(
|
|
state: PhysicalAttemptState,
|
|
isCommand: boolean,
|
|
): MutationEffectCertainty {
|
|
if (!isCommand) return "NOT_STARTED";
|
|
switch (state) {
|
|
case "NOT_STARTED":
|
|
case "PREPARING":
|
|
case "READY_TO_SEND":
|
|
return "NOT_STARTED";
|
|
default:
|
|
return "MAYBE_APPLIED";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* §8.7. The conservative certainty lattice for one logical execution.
|
|
*
|
|
* `PhysicalAttemptState` describes only the attempt in flight. A new retry that
|
|
* has not been sent yet must never lower what an earlier attempt already
|
|
* established, so the executor joins observations into a monotonic accumulator.
|
|
*/
|
|
const CERTAINTY_RANK: Readonly<Record<MutationEffectCertainty, number>> =
|
|
Object.freeze({
|
|
NOT_STARTED: 0,
|
|
NOT_APPLIED: 1,
|
|
MAYBE_APPLIED: 2,
|
|
APPLIED_CONFIRMED: 3,
|
|
});
|
|
|
|
export function joinMutationEffectCertainty(
|
|
current: MutationEffectCertainty,
|
|
observed: MutationEffectCertainty,
|
|
): MutationEffectCertainty {
|
|
return CERTAINTY_RANK[observed] > CERTAINTY_RANK[current]
|
|
? observed
|
|
: current;
|
|
}
|
|
|
|
export type ProblemEffectInput<Problem> = Readonly<{
|
|
status: number;
|
|
problem: Problem;
|
|
descriptor: CommandEffectDescriptor<Problem> | null;
|
|
}>;
|
|
|
|
export type ProblemEffectOutcome = Readonly<{
|
|
effect: MutationEffectCertainty;
|
|
contractRuntimeFailure: boolean;
|
|
}>;
|
|
|
|
const CLASSIFICATIONS: ReadonlySet<CommandEffectClassification> = new Set([
|
|
"NOT_APPLIED",
|
|
"APPLIED_CONFIRMED",
|
|
"MAYBE_APPLIED",
|
|
]);
|
|
|
|
/**
|
|
* §4.4. The classifier is package-owned and pure. A throw or an unrecognised
|
|
* return value fails safe to `MAYBE_APPLIED` and is recorded as a contract
|
|
* runtime failure rather than being silently treated as "not applied".
|
|
*/
|
|
export function classifyProblemEffect<Problem>(
|
|
input: ProblemEffectInput<Problem>,
|
|
): ProblemEffectOutcome {
|
|
if (!input.descriptor) {
|
|
// A read operation carries no command effect; there is nothing to apply.
|
|
return Object.freeze({
|
|
effect: "NOT_STARTED" as const,
|
|
contractRuntimeFailure: false,
|
|
});
|
|
}
|
|
let classification: CommandEffectClassification;
|
|
try {
|
|
classification = input.descriptor.classifyProblem({
|
|
status: input.status,
|
|
problem: input.problem,
|
|
});
|
|
} catch {
|
|
return Object.freeze({
|
|
effect: "MAYBE_APPLIED" as const,
|
|
contractRuntimeFailure: true,
|
|
});
|
|
}
|
|
if (!CLASSIFICATIONS.has(classification)) {
|
|
return Object.freeze({
|
|
effect: "MAYBE_APPLIED" as const,
|
|
contractRuntimeFailure: true,
|
|
});
|
|
}
|
|
return Object.freeze({
|
|
effect: classification,
|
|
contractRuntimeFailure: false,
|
|
});
|
|
}
|
|
|
|
/** §8.10. Certainty to UI intent. The copy itself is owned by the i18n catalog. */
|
|
export function projectCertaintyToUi(
|
|
certainty: MutationEffectCertainty,
|
|
): "RETRYABLE" | "CHECK_STATUS" | "SUCCESS" {
|
|
switch (certainty) {
|
|
case "APPLIED_CONFIRMED":
|
|
return "SUCCESS";
|
|
case "MAYBE_APPLIED":
|
|
return "CHECK_STATUS";
|
|
default:
|
|
return "RETRYABLE";
|
|
}
|
|
}
|