From eea2995ac1bc8ee8e9173b92657aa8c6e785f1db Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Mon, 28 Sep 2026 11:23:34 -0400 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9C=A8=20Run=20spawned=20document=20wo?= =?UTF-8?q?rk=20concurrently=20with=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `` runs its direct `` children at the same time and waits for all of them. Both names are engine structural syntax, so no repository file, registration, bundle or Plugin can supply either, and they work in ordinary and admitted generated XMD alike. One shared pure rule decides the whole structure from source — paired forms, no props, at least two spawns, blank text only between them, no `` outside its ``, and no `` or `` reaching past a spawn — and expansion, non-executing validation and the whole-fragment preflight read the same result, so a malformed construct starts no child anywhere. Each child is a durable coroutine of the one that reached the ``, allocated in source order by the existing `durableAll()` join, with its own binding environment, live overlay, eval scope, block counter, output buffer, failure ledger, hide set and expansion path. Nothing merges back. `` appends the renderings in authored order only after every child succeeds, so completion order may decide when records append and never what the document renders. The first failure cancels and joins the rest, publishes nothing, and fabricates no completion. Capability-backed identity becomes branch-local, which is what the Story's own `` example needs. Canonical import frames and provider answer windows were kept as one execution-wide last-open stack, so two children resolving at once could have one child's selection land in the other's frame — an ordinary `` in each branch then named no durable identity at all. Both stacks are now owned per Effection scope: nesting inside one scope still hides its parent until it closes, sibling branches have independent tops, closing or cancelling one neither clears nor authorizes the other, and a provider installation may answer in two open windows while a second, different answer in either still refuses. The scope is a private key and reaches no document, component or provider. `All` and `Spawn` join the two frozen complete structural-vocabulary expectations, which is what failed the earlier weights run. --- architecture.md | 100 +- packages/cli/tests/syntax-cli.test.ts | 2 + packages/core/src/body-structure.ts | 9 +- packages/core/src/component-answers.ts | 7 +- packages/core/src/component-failures.ts | 23 +- .../src/components/component-resolution.ts | 121 +- packages/core/src/document-validation.ts | 42 +- packages/core/src/execute.ts | 31 +- packages/core/src/expand.ts | 197 ++- packages/core/src/generated-xmd.ts | 19 +- packages/core/src/invocation-identity.ts | 76 +- packages/core/src/structural-rules.ts | 201 +++ packages/core/src/structural.ts | 21 + packages/core/tests/all.test.ts | 1489 +++++++++++++++++ packages/core/tests/answer-identity.test.ts | 863 ++++++++-- .../core/tests/invocation-identity.test.ts | 76 +- packages/core/tests/syntax-catalog.test.ts | 2 + specs/executable-mdx-spec.md | 92 + 18 files changed, 3093 insertions(+), 278 deletions(-) create mode 100644 packages/core/tests/all.test.ts diff --git a/architecture.md b/architecture.md index fa26f8e2c..abb42ecc6 100644 --- a/architecture.md +++ b/architecture.md @@ -1743,8 +1743,8 @@ component neither imports it nor grants its effects. Bindings and structural constructs are engine-owned language syntax and require no profile entry. Every built-in construct is available inside a generated fragment with its ordinary semantics — `Content`, `Output`, `Return`, `Let`, -`Each`, `If`, `Else`, `Switch`, `Case`, `Loop`, `Break`, `PrintErrors`, -`Answers` and `Answer` — decided by the same source rules ordinary validation +`Each`, `If`, `Else`, `Switch`, `Case`, `Loop`, `Break`, `All`, `Spawn`, +`PrintErrors`, `Answers` and `Answer` — decided by the same source rules ordinary validation and expansion read, so a construct means one thing whether a person or an Agent wrote it. Preflight dispatches a reserved name to those rules before the admitted table is consulted, which is why a construct is never reported as a @@ -1766,8 +1766,10 @@ nothing it binds survives it, because that body may run no times at all — only `` branches of a `` are checked from one incoming snapshot, so no alternative supplies a binding to another; the union of what they can produce becomes visible afterwards, which keeps reading a binding only one arm makes a -runtime failure rather than a preflight refusal. ``, `` and -`` bodies read and write the enclosing environment. Constructs keep their +runtime failure rather than a preflight refusal. Each `` under an `` +is checked from that same incoming snapshot and contributes nothing back, which +is the binding contract the children actually run under. ``, +`` and `` bodies read and write the enclosing environment. Constructs keep their exact spelling in the retained source, never join the retained named-component list, and change no record version. @@ -3197,6 +3199,9 @@ for the loop it exits. One state exists per execution of one value body. ``, ``, ``, `` and `` keep the ambient one; a component invocation hides the caller's from the invoked body, so a component's own `` satisfies its own declaration; a +`` passes none either, and the shared rule refuses the `` that +would have reached for one, so concurrent children cannot race to claim a value +owned outside their ``; a nested value body installs a separate one, and both executions stand; and content the caller projected restores the caller's, through a Markdown `` and a function component's `content()` alike, with every @@ -3279,6 +3284,60 @@ partial replay rebuilds the selection through ordinary expansion while completed effects in the chosen branch replay from their own records, and a completed document replay reuses the retained result without expanding anything. +### Concurrent spawned children + +`` and `` are the engine's own syntax, not components, so core owns +what they mean and no repository file, registration, bundle or Plugin can supply +either name. `` runs its direct `` children at the same time and +waits for all of them. It takes no props, produces no value, and requires at +least two spawns — one alone is the sequential document it was already written +as. + +The whole structure is decided from source before a child is constructed: the +paired forms, the absent props, the two-spawn minimum, that only blank text sits +between the spawns, that no `` is written outside its direct ``, and +that no `` or `` inside a spawn reaches for an owner outside it. +One shared rule states all of it, and expansion, non-executing validation and +the generated-fragment preflight read the same result — so a malformed construct +starts no child anywhere, including in a fragment an Agent generated. + +**Concurrent expansion shares immutable inputs and nothing else.** Every child +gets a binding environment and live overlay snapshotted from the one that +reached the ``, an eval scope of its own, a fresh block counter, a private +output buffer, its own checked-failure ledger, a copied hide set and an +expansion path extended by its authored ordinal. Nothing merges back, so a name +one child binds or rebinds is invisible to its siblings and to the work after +``, and a resource it retains is released when it ends. The outer +`` and `` owners are cleared at the boundary; a loop or value +component created wholly inside a child establishes its own. + +**Durable identity comes from the source, never from the schedule.** The +existing durable structured-concurrency substrate is the implementation: in +source order, before any child starts, each `` receives one child +coroutine of the one that reached the ``, and nesting produces the existing +hierarchical identity. Effects inside a child keep their ordinary descriptions +under that coroutine, so two children may derive the same local block id without +colliding, and work after `` continues on the parent counter it would have +had without any child. Each successful child closes with its rendered string. + +**Output is authored order; the journal is completion order.** A child emits +into its private buffer, and `` appends the renderings to its caller's +region only after every child has succeeded. Which child finished first may +decide when its records append and never what the document renders. A complete +replay reads the child closes and runs no spawned work; a partial replay +restores the children that closed and resumes only the unrecorded ones under the +same identities. Inserting, removing or reordering spawns is a definition change +and takes the existing divergence path rather than being reassigned by position +or completion time. + +**Failure is the existing fail-fast join.** The first child failure fails the +``, cancels every unfinished sibling and does not return until all of them +have finished tearing down. No private buffer is emitted, records acknowledged +before the failure stay durable, and interrupted work is never recorded as +complete. Cancelling the parent takes the same ownership path, and no task, +subscription, retained resource or buffer survives its spawn. No scheduler, no +new record family and no document-visible concurrency control is introduced. + ## Foreground commands An executable block is a foreground child process. Its output reaches the reader @@ -3930,7 +3989,7 @@ matching name says nothing about which registration answered. What settles it is the selection itself, recorded where it is made: - expansion opens an **execution-private import frame** before it asks the - public import chain anything; + public import chain anything, in the Effection scope that is asking; - canonical core resolution records, inside that frame, the exact name it was asked for and the exact implementation it selected — the function object this execution built from the host's factory, by identity; @@ -3947,10 +4006,33 @@ provenance and no permission: what a handler decides is which implementation runs, and an implementation running where canonical resolution did not select it names nothing. Nested and re-entrant frames stay contained, because a frame is opened per import and settled the moment that import answers, however it -answered; concurrent interleaving leaves more than one selection in a frame and -so yields no domain, which is the safe direction; and a replay decides the same -way, against this execution's own factory-created implementation rather than -against anything a previous run recorded. +answered; and a replay decides the same way, against this execution's own +factory-created implementation rather than against anything a previous run +recorded. + +**Frames are owned per Effection scope, not per execution.** `` gives two +`` children imports in flight at the same time, so "the frame this +selection belongs to" can no longer mean "the last one anybody opened". Each +scope keeps its own LIFO stack of open frames, and a canonical selection is +recorded into the top frame of the scope that is resolving: + +- nesting inside one scope is unchanged — an inner import owns the top until it + closes, and the outer one may be selected into again afterwards; +- sibling branches have independent tops, so one child's selection can never + land in another's frame, and closing or cancelling one branch neither clears + nor authorizes the other; +- a frame is removed only by the settle that opened it, from the scope that + opened it, and teardown discards every remaining stack; and +- two selections in *one* frame — a handler delegating twice — still yield no + domain, which remains the safe direction. + +The scope object is a private key. It is never published, never read from, and +never reaches a document, a component, a provider or a handler: two frames +belong together because they were opened under the same engine scope, not +because of anything either of them says. The same ownership governs the +canonical answer windows a provider claims through, where one installation may +hold an answer open in two branches at once and a second, different answer in +either still refuses. The engine then mints one issuance per invocation, carrying that domain — or none — the authored name for what a refusal says, and the frame the body is diff --git a/packages/cli/tests/syntax-cli.test.ts b/packages/cli/tests/syntax-cli.test.ts index 957363ea3..6967d4509 100644 --- a/packages/cli/tests/syntax-cli.test.ts +++ b/packages/cli/tests/syntax-cli.test.ts @@ -326,6 +326,7 @@ describe("Tier SX — the run profile the command describes", () => { // The whole structural vocabulary this profile publishes, so a construct // returning to it has to be written down here. expect([...names(structural.entries)].sort()).toEqual([ + "All", "Answer", "Answers", "Break", @@ -339,6 +340,7 @@ describe("Tier SX — the run profile the command describes", () => { "Output", "PrintErrors", "Return", + "Spawn", "Switch", ]); for (const name of ["Terminal.Grid", "Terminal"]) { diff --git a/packages/core/src/body-structure.ts b/packages/core/src/body-structure.ts index c0ff0c689..99e241429 100644 --- a/packages/core/src/body-structure.ts +++ b/packages/core/src/body-structure.ts @@ -81,13 +81,20 @@ function collectOutputs(bodySegments: Segment[], minimumDepth: number): Componen * this walk does not see is the only thing that still cannot declare one — * another component's definition, and markdown produced at runtime — because * it reads this body's source AST and nothing else. + * + * A `` is the one region of this body's own source the walk stops at. + * The spawned child owns no value body, so a `` inside one neither + * satisfies this body's declaration nor is an undeclared return of it: the + * `` rule owns that diagnostic, and counting it here would report one + * mistake as two while letting a spawn stand in for the return the body still + * has to write. */ function collectReturns(bodySegments: Segment[]): ComponentElement[] { const declared: ComponentElement[] = []; const walk = (segments: Segment[]): void => { for (const segment of segments) { - if (segment.type !== "component") { + if (segment.type !== "component" || segment.name === "Spawn") { continue; } if (segment.name === "Return") { diff --git a/packages/core/src/component-answers.ts b/packages/core/src/component-answers.ts index 3ce4d1a22..abaf1acf4 100644 --- a/packages/core/src/component-answers.ts +++ b/packages/core/src/component-answers.ts @@ -39,6 +39,7 @@ * do is enter an admitted fragment. */ +import { useScope } from "effection"; import type { Operation } from "effection"; import { Component } from "./component-api.ts"; @@ -114,7 +115,11 @@ export function componentAnswerRegistrar( *around(handler: ComponentAnswerHandler): Operation { yield* Component.around({ *importComponent([name, position], next) { - const asked = installation.open(name, position); + // The scope this invocation is running in, which is the branch whose + // resolution this request answers. Read here rather than carried on + // the installation: one installation serves every branch, and two of + // them may be resolving at the same time. + const asked = installation.open(yield* useScope(), name, position); try { return yield* handler( asked.request, diff --git a/packages/core/src/component-failures.ts b/packages/core/src/component-failures.ts index fb8bc2c3d..9db405ed2 100644 --- a/packages/core/src/component-failures.ts +++ b/packages/core/src/component-failures.ts @@ -20,7 +20,7 @@ */ import { Component, raise } from "./component-api.ts"; -import { attributeCause, ErrorMode } from "./errors.ts"; +import { attributeCause, documentationError, ErrorMode } from "./errors.ts"; import type { ComponentFailure, ErrorSegment, FunctionComponent } from "./types.ts"; import type { Operation } from "effection"; @@ -92,6 +92,27 @@ export function containedLedger(inherited: CheckedFailures | undefined): Checked return { authorized: inherited?.authorized ?? false }; } +/** + * Refuse a successful outcome for work that suffered an unauthorized checked + * command failure. + * + * The failure was already raised where the command ran, and something enclosing + * it — a `printErrors(fn)` component like ``, or one that caught the + * `ContentError` its projected content raised — printed it and returned. Those + * boundaries decide how a failure of their own is reported. Whether a command + * that exited nonzero failed the run is not theirs to decide (#441). + * + * Whoever owns the ledger says so: the execution for the run's own, and a + * spawned child for the one it keeps to itself, which is how a checked failure + * inside one `` fails that child rather than stopping a sibling's walk. + */ +export function* refuseCheckedFailure(checkedFailures: CheckedFailures): Operation { + const segment = checkedFailures.failure; + if (segment !== undefined) { + throw yield* documentationError(segment, "output"); + } +} + /** * Continue after this component fails, reporting the failure as a printed error. * diff --git a/packages/core/src/components/component-resolution.ts b/packages/core/src/components/component-resolution.ts index e46a6c1f3..361267d42 100644 --- a/packages/core/src/components/component-resolution.ts +++ b/packages/core/src/components/component-resolution.ts @@ -18,6 +18,8 @@ * nothing a handler still holds decides what is *invoked*. */ +import type { Scope } from "effection"; + import type { ComponentDefinition, FunctionComponentDefinition, SourcePosition } from "../types.ts"; /** A definition an import may answer with. */ @@ -300,8 +302,15 @@ export interface OpenAnswerRequest { * cannot revive a settled one or reach another provider's. */ export interface ProviderInstallation { - /** Begin one handler invocation's request for one asked name. */ - open(name: string, position?: Readonly): OpenAnswerRequest; + /** + * Begin one handler invocation's request for one asked name, under the engine + * scope that is resolving it. + * + * The scope is how the request finds the resolution it was asked in when + * several are open at once. It is a private key the caller reads from its own + * operation; nothing about it reaches the provider. + */ + open(scope: Scope, name: string, position?: Readonly): OpenAnswerRequest; } /** An identity a provider stated in a shape this execution cannot record. */ @@ -335,7 +344,7 @@ export class CanonicalImports { */ #active = false; /** - * The one resolution a claim may be stated during, when one is open. + * The resolutions each Effection scope has open, innermost last. * * A provider installation outlives every resolution it takes part in, while a * fresh request belongs to one handler invocation. Canonical execution asks @@ -348,25 +357,36 @@ export class CanonicalImports { * belonging to a resolution other than the live one, and the name keeps a * handler settled for one name from recording under it while a different * name is being resolved. + * + * A stack per scope rather than one for the execution, because independent + * branches resolve at the same time. Nesting inside one scope stays LIFO — + * an inner resolution hides its parent until it closes — while a sibling + * branch has its own top, so closing or cancelling one can neither clear nor + * authorize the other. The scope object is a private key: never published, + * never read from, and never handed to a provider. */ - #window: ResolutionWindow | undefined; + readonly #windows = new Map(); /** How many resolutions this owner has opened, so each one is its own. */ #occurrences = 0; /** - * The resolution each installation last stated an answer for. + * The resolutions each installation has already stated an answer for. * * Secondary. What proves a statement belongs to an import is the request's * captured window, not this; this only keeps one provider from naming two * different implementations for one import, where only one of them could be * what it resolved to. * - * Keyed by the installation's own frozen token and holding the window object, - * so an installation stays reusable: it answers several admitted names and - * the same name resolved more than once, because each of those is a different - * window. Spending the installation itself would break a valid multi-name - * provider, which the contract does not ask a host to split up. + * A set of windows per installation rather than the last one it answered. + * Two windows can be open at once now, so one installation may legitimately + * answer in window A and then in window B — and a second, different answer + * in A must still refuse, even though B was answered in between. Remembering + * only the most recent window would have let that second answer through. + * + * Keyed by the installation's own frozen token, so an installation stays + * reusable: it answers several admitted names and the same name resolved more + * than once, because each of those is a different window. */ - readonly #spent = new WeakMap(); + readonly #spent = new WeakMap>(); /** Begin identifying. Called after teardown is registered. */ activate(): void { @@ -376,7 +396,9 @@ export class CanonicalImports { /** Stop. Called at teardown, on completion, failure or cancellation. */ revoke(): void { this.#active = false; - this.#window = undefined; + // Every scope's stack, not only the ones that emptied themselves: a branch + // torn down with a resolution still open leaves nothing claimable. + this.#windows.clear(); } get identifying(): boolean { @@ -392,7 +414,7 @@ export class CanonicalImports { * one: there is no path from a document, a component or a provider to this * method. */ - beginResolution(name: string): ResolutionWindow { + beginResolution(name: string, scope: Scope): ResolutionWindow { if (!this.#active) { throw new AnswerIdentityError(REVOKED_ANSWER_IDENTIFICATION); } @@ -403,16 +425,31 @@ export class CanonicalImports { name, occurrence, close(): void { - // Only this window is closed. A nested resolution that already replaced - // it has its own close, and clearing another one here would settle a - // decision still being made. Compared by identity, so no bookkeeping - // value has to be trusted to say which window this is. - if (owner.#window === window) { - owner.#window = undefined; + // Only this window, and only out of the scope that opened it. A nested + // resolution above it has its own close, and a sibling branch's stack + // is not touched at all — clearing either would settle a decision still + // being made somewhere else. Removed by identity, so no bookkeeping + // value has to be trusted to say which window this is, and idempotent, + // because a close that ran twice would otherwise remove its parent. + const open = owner.#windows.get(scope); + if (open === undefined) { + return; + } + const index = open.lastIndexOf(window); + if (index >= 0) { + open.splice(index, 1); + } + if (open.length === 0) { + owner.#windows.delete(scope); } }, }; - this.#window = window; + const open = this.#windows.get(scope); + if (open === undefined) { + this.#windows.set(scope, [window]); + } else { + open.push(window); + } return window; } @@ -434,12 +471,13 @@ export class CanonicalImports { const installation = Object.freeze({}); const owner = this; return { - open(name: string, position?: Readonly): OpenAnswerRequest { - // Captured by identity, here, at the moment this invocation begins. A - // request minted while resolution N is open answers resolution N or - // nothing: it holds the object, so it cannot be made to describe - // whichever window is open later. - const opened = owner.#window; + open(scope: Scope, name: string, position?: Readonly): OpenAnswerRequest { + // Captured by identity, here, at the moment this invocation begins, out + // of the scope that is resolving. A request minted while resolution N + // is open answers resolution N or nothing: it holds the object, so it + // cannot be made to describe whichever window is open later — or a + // window a different branch opened in the meantime. + const opened = owner.#windows.get(scope)?.at(-1); let live = true; const request: ComponentAnswerRequest = Object.freeze({ name, @@ -452,7 +490,7 @@ export class CanonicalImports { return owner.#record( installation, origin, - { name, window: opened, live: () => live }, + { name, window: opened, scope, live: () => live }, answer, stated, ); @@ -471,7 +509,12 @@ export class CanonicalImports { #record( installation: object, origin: string, - asked: { name: string; window: ResolutionWindow | undefined; live: () => boolean }, + asked: { + name: string; + window: ResolutionWindow | undefined; + scope: Scope; + live: () => boolean; + }, answer: ImportedDefinition, stated: ClaimedIdentity, ): ImportedDefinition { @@ -483,8 +526,12 @@ export class CanonicalImports { // was asked in the one still open, by identity; and is the name it was // asked the name that resolution is deciding. A stable installation handle // answers none of them, which is why it does not claim. + // Four questions, and the window one is asked of the scope that resolved: + // being the innermost open resolution somewhere else in the execution is + // not being the one this handler was asked in. const open = asked.window; - if (!asked.live() || open === undefined || open !== this.#window || open.name !== asked.name) { + const top = this.#windows.get(asked.scope)?.at(-1); + if (!asked.live() || open === undefined || open !== top || open.name !== asked.name) { throw new AnswerIdentityError(SETTLED_CLAIM); } const identity = complete(origin, stated); @@ -514,7 +561,7 @@ export class CanonicalImports { // Secondary, and about the provider rather than the invocation: naming a // *different* implementation for an import this provider already answered // is two answers where only one could be what it resolved to. - if (this.#spent.get(installation) === open) { + if (this.#spent.get(installation)?.has(open) === true) { throw new AnswerIdentityError(SPENT_OPPORTUNITY); } // Copied on the way in, so a later edit of the claimed object is visible as @@ -526,10 +573,16 @@ export class CanonicalImports { window: open, canonical: retain(answer), }); - // Spent for this window and no other: the next import is a different - // window, which is what lets one installation answer several admitted - // names and the same name resolved twice. - this.#spent.set(installation, open); + // Spent for this window and no other: another import is a different window, + // which is what lets one installation answer several admitted names, the + // same name resolved twice, and two branches resolving at the same time — + // while a second answer in a window it already spent still refuses. + const spent = this.#spent.get(installation); + if (spent === undefined) { + this.#spent.set(installation, new WeakSet([open])); + } else { + spent.add(open); + } return answer; } diff --git a/packages/core/src/document-validation.ts b/packages/core/src/document-validation.ts index 431886045..ef8b19235 100644 --- a/packages/core/src/document-validation.ts +++ b/packages/core/src/document-validation.ts @@ -61,6 +61,7 @@ import { readRootSource, rootSourcePath } from "./root-source.ts"; import { composeRootDefinition } from "./root-composition.ts"; import type { RootDocumentSource } from "./root-source.ts"; import { + allStructure, answersViolations, answerViolations, breakViolations, @@ -74,6 +75,7 @@ import { strayAnswerMessage, strayCaseMessage, strayElseMessage, + straySpawnMessage, strayStructuralMessage, switchStructure, } from "./structural-rules.ts"; @@ -315,6 +317,16 @@ interface LexicalContext { readonly insideIf: boolean; /** Whether a `` in this source lexically encloses this point. */ readonly insideSwitch: boolean; + /** + * Whether a `` in this source lexically encloses this point. + * + * A spawned child owns no value body and no loop it did not open itself, so + * this is what tells a `` written inside one from the ordinary + * `` of the body it was written in. It never clears again within one + * source: a definition invoked inside the child is its own source and starts + * the walk over. + */ + readonly insideSpawn: boolean; /** Whether the immediate parent is an ``. */ readonly underAnswers: boolean; /** @@ -500,6 +512,7 @@ class ValidationState { insideLoop: false, insideIf: false, insideSwitch: false, + insideSpawn: false, underAnswers: false, enclosing: undefined, }); @@ -1144,8 +1157,25 @@ class ValidationState { return switchStructure(segment).violations; case "Loop": return loopViolations(segment); + case "All": + // Every child's own source is decided here too, so a malformed + // `` — and a `` or `` that would leave one — is + // reported wherever it was written, before any child could start. + return allStructure(segment).violations; + case "Spawn": + // A well-placed `` is its ``'s, and one placed wrongly + // under an `` is already reported by that ``'s own structure. + // What is left is a `` with no `` above it at all. + return context.enclosing === "All" + ? [] + : [{ code: "structural-usage-invalid", source: "Spawn", message: straySpawnMessage() }]; case "Break": - return breakViolations(segment, context.insideLoop); + // A `` reaching past its spawn is already reported by that + // spawn's ``, which says what is actually wrong with it — the loop + // it reached for is outside the child — rather than that no loop exists. + return context.insideSpawn && !context.insideLoop + ? [] + : breakViolations(segment, context.insideLoop); case "PrintErrors": return printErrorsViolations(segment); case "Answers": @@ -1195,7 +1225,8 @@ class ValidationState { default: // `` is the remaining case, and its whole contract belongs to // the body that declares — or fails to declare — `returns`, which the - // source's own facts already stated. + // source's own facts already stated. One written inside a `` + // belongs to no such body, and is reported by that spawn's ``. return []; } } @@ -1331,12 +1362,17 @@ function hasDynamicOperand(segment: ComponentElement): boolean { /** The lexical facts one element's children are written under. */ function childContext(segment: ComponentElement, context: LexicalContext): LexicalContext { + const spawned = segment.name === "Spawn"; return { entry: context.entry, isRoot: context.isRoot, - insideLoop: context.insideLoop || segment.name === "Loop", + // A spawn is a control-flow boundary: the loop that encloses the `` is + // not a loop its children may break, so the outer fact stops here and only + // a `` written inside the spawn opens a new one. + insideLoop: !spawned && (context.insideLoop || segment.name === "Loop"), insideIf: context.insideIf || segment.name === "If", insideSwitch: context.insideSwitch || segment.name === "Switch", + insideSpawn: context.insideSpawn || spawned, underAnswers: segment.name === "Answers", enclosing: segment.name, }; diff --git a/packages/core/src/execute.ts b/packages/core/src/execute.ts index 1964e8588..a0b3bc8aa 100644 --- a/packages/core/src/execute.ts +++ b/packages/core/src/execute.ts @@ -10,7 +10,7 @@ * See DEC-005 in specs/decisions.md. */ -import { Err, Ok, ensure, scoped, spawn, withResolvers, until } from "effection"; +import { Err, Ok, ensure, scoped, spawn, useScope, withResolvers, until } from "effection"; import type { Operation, Result, Stream } from "effection"; import { type Api, createApi, type Operations } from "@effectionx/context-api"; import { @@ -181,7 +181,7 @@ import type { RootDocumentSource } from "./root-source.ts"; import { useEvalScope } from "@effectionx/scope-eval"; import { declaredRouting, FOREGROUND, route, withRouting } from "./foreground.ts"; import type { ForegroundRouting } from "./foreground.ts"; -import { checkedFailureLedger } from "./component-failures.ts"; +import { checkedFailureLedger, refuseCheckedFailure } from "./component-failures.ts"; import { provideTestHarnessInstallers } from "./test-harness.ts"; import type { TestHarnessInstaller } from "./test-harness.ts"; import type { CheckedFailures } from "./component-failures.ts"; @@ -846,7 +846,7 @@ function* resolveComponentAnswers( ) { return answer; } - const asked = canonicalProvider.open(name, position); + const asked = canonicalProvider.open(yield* useScope(), name, position); try { return asked.request.claim(answer, { key: name, revision: CORE_REVISION }); } finally { @@ -866,7 +866,7 @@ function* resolveComponentAnswers( // One call, one result. The claim and core's copy of what was claimed // come back together, and the object the chain returned is not read // again — so nothing this run keeps was decided by a second read. - const resolution = imports.beginResolution(name); + const resolution = imports.beginResolution(name, yield* useScope()); let identified; try { // The resolution this run opened is handed to identification rather @@ -2073,24 +2073,6 @@ function* runValueRoot( return { status: "ok", output: chunks.join(""), value: selected.value }; } -/** - * Refuse a successful outcome for a run that suffered an unauthorized checked - * command failure. - * - * The failure was already raised where the command ran, and something enclosing - * it — a `printErrors(fn)` component like ``, or one that caught the - * `ContentError` its projected content raised — printed it and returned. Those - * boundaries decide how a failure of their own is reported. Whether a command - * that exited nonzero failed the run is not theirs to decide, and this is where - * the run says so (#441). - */ -function* refuseCheckedFailure(checkedFailures: CheckedFailures): Operation { - const segment = checkedFailures.failure; - if (segment !== undefined) { - throw yield* documentationError(segment, "output"); - } -} - function* documentWorkflow( props: Record, environment: ExecutionEnvironment, @@ -2653,7 +2635,10 @@ function* executeDocument( // domains: not the name, not the answer that comes back, and // nothing a handler above this can hold (`invocation-identity.ts`). if (definition.kind === "function") { - identity.identities.select(name, definition); + // Recorded into the frame the scope that is resolving opened, + // rather than into whichever import happens to be innermost + // across the whole execution. + identity.identities.select(name, definition, yield* useScope()); // The same record, for the other thing canonical resolution // decides here: which dispatcher — if any — this import selected. // A dispatcher a handler kept from another import reaches no body diff --git a/packages/core/src/expand.ts b/packages/core/src/expand.ts index 2b96bf923..1f563cc53 100644 --- a/packages/core/src/expand.ts +++ b/packages/core/src/expand.ts @@ -13,7 +13,7 @@ * middleware installation) execute before children's code blocks. */ -import { ensure, Err, Ok, scoped, useScope, withResolvers } from "effection"; +import { all, ensure, Err, Ok, scoped, useScope, withResolvers } from "effection"; import type { Operation, Result, Stream } from "effection"; import type { FunctionComponent, @@ -39,6 +39,7 @@ import { validateOutputPlacement, } from "./body-structure.ts"; import { + allStructure, breakElementViolations, eachCaptureBinding, eachItemBinding, @@ -56,10 +57,11 @@ import { strayBreakMessage, strayCaseMessage, strayElseMessage, + straySpawnMessage, strayStructuralMessage, switchStructure, } from "./structural-rules.ts"; -import type { StructuralViolation, SwitchCase } from "./structural-rules.ts"; +import type { SpawnRegion, StructuralViolation, SwitchCase } from "./structural-rules.ts"; import { asBindingViolation, asExpressionViolation, @@ -103,7 +105,7 @@ import type { import { regionStream } from "./expansion-region.ts"; import { emissions } from "./render.ts"; import { printsErrors, usePrintErrors } from "./component-failures.ts"; -import { containedLedger, recoveringLedger } from "./component-failures.ts"; +import { containedLedger, recoveringLedger, refuseCheckedFailure } from "./component-failures.ts"; import type { CheckedFailures } from "./component-failures.ts"; import type { ImportedDefinition } from "./components/component-resolution.ts"; import type { ExecutionEnvironment } from "./execution-environment.ts"; @@ -129,6 +131,8 @@ import { createReturnBody, missingReturnMessage } from "./return-flow.ts"; import type { ReturnBody } from "./return-flow.ts"; import { unbox, useEvalScope } from "@effectionx/scope-eval"; import type { EvalScope } from "@effectionx/scope-eval"; +import { DurableContext, durableAll, ephemeral } from "@executablemd/durable-streams"; +import type { Workflow } from "@executablemd/durable-streams"; import { SchemaValidationError, validateProps, validateReturnValue } from "./validate.ts"; import { parseJson } from "./json.ts"; import { healSegment } from "./heal.ts"; @@ -1190,6 +1194,37 @@ function* expandListSegments( break; } + if (segment.name === "All") { + // No raise() here, like the branches above: expandAll reports the + // errors it creates, and each child settled its own (§6.9). + yield* expandAll( + segment, + parentMeta, + parentProps, + hideSet, + result, + elementPath, + checkedFailures, + environment, + ); + break; + } + + if (segment.name === "Spawn") { + // A well-placed is consumed by its and never expanded on + // its own. Reaching this branch means the element sits outside any + // , so it names no component and is diagnosed rather than + // resolved from the filesystem. + result.push( + yield* raise({ + type: "error", + message: positioned(straySpawnMessage(), segment), + source: "Spawn", + }), + ); + break; + } + if (RESERVED_STRUCTURAL.has(segment.name)) { // Every other structural name is consumed above; reaching here means // one was written where the construct that gives it meaning is not. @@ -2270,6 +2305,157 @@ function* expandBreak( return reported; } +/** + * The environment one spawned child starts from (spec §6.5 ``). + * + * Shallow snapshots of both maps: the durable values the `` was reached + * with, and the private live overlay beside them. Ordinary binding values are + * carried by identity — isolating what an author deliberately bound inside an + * object is not this construct's business — while the maps themselves are the + * child's own, so a name one child binds or rebinds is invisible to its + * siblings and to the work after ``. + */ +function spawnEnvironment(incoming: EvalEnv | undefined): EvalEnv { + const child: EvalEnv = { values: { ...(incoming?.values ?? {}) } }; + const overlay = liveEnvironment(child); + if (incoming !== undefined) { + Object.assign(overlay.values, liveEnvironment(incoming).values); + } + return child; +} + +/** + * Expand one `` body into the string its child closes with. + * + * Everything mutable the ordinary walk threads is allocated here rather than + * inherited: the binding environment and its live overlay, an eval scope the + * child owns and whose resources die with it, a block counter, a private + * segment buffer, a checked-failure ledger and a copy of the hide set. + * Concurrent children therefore share immutable inputs and nothing else. + * + * The outer `` and `` owners are cleared: several children + * running at once may not race to select one enclosing value or decide one + * enclosing loop, and the structural rule already refused the elements that + * would try. A `` or value component created wholly inside the child + * establishes its own owner exactly as it does anywhere else. + */ +function spawnChild( + spawn: SpawnRegion, + incoming: EvalEnv | undefined, + parentMeta: Record, + parentProps: Record, + hideSet: Set, + path: string, + inherited: CheckedFailures | undefined, + environment: ExecutionEnvironment | undefined, +): Operation { + return scoped(function* () { + yield* provideEnv(spawnEnvironment(incoming)); + yield* provideEvalScope(yield* useEvalScope()); + yield* ActiveLoop.set(undefined); + // The `` is consumed by its `` and never reaches dispatch, so + // its frame is added here — otherwise every child of one `` would + // expand under one path (§5.6). + const childPath = extendPath( + path, + elementFrame(spawn.element.name, elementSite(spawn.element.position, spawn.ordinal)), + ); + const segments: Segment[] = []; + // A fresh record with the inherited recovery, like a contained invocation's: + // a checked command failure inside one child fails that child, and a + // sibling's walk is not stopped by a ledger it does not own. + const ledger = containedLedger(inherited); + yield* expandSegmentsWithin( + spawn.element.children, + parentMeta, + parentProps, + new Set(hideSet), + createBlockCounter(), + segments, + childPath, + 0, + ledger, + environment, + undefined, + ); + yield* refuseCheckedFailure(ledger); + return renderSegments(segments); + }); +} + +/** + * Run the children of an `` at the same time (spec §6.5 ``). + * + * The children are durable coroutines of the one that reached the ``, + * allocated in source order before any of them starts, so identity comes from + * where a `` was written and never from the order work was scheduled in. + * `durableAll()` is the whole join: it allocates those identities, returns the + * results in input order, reuses a completed child's recorded close on replay, + * and cancels unfinished siblings when one fails. + * + * Nothing is appended until the join succeeds. Each child renders into a buffer + * of its own, and the strings are written to the caller's region in authored + * order afterwards — so which child finished first may decide when its durable + * records append, and never what the document renders. A failed or cancelled + * join appends none of them. + * + * Expansion driven without a journal — a test, a tool describing a document — + * runs the same children on the same join without durable identities, exactly + * as `` records nothing there and behaves identically otherwise. + */ +function* expandAll( + segment: ComponentElement, + parentMeta: Record, + parentProps: Record, + hideSet: Set, + /** The region this renders into, once every child has succeeded. */ + owner: Segment[], + path: string, + /** Whether the enclosing region grants checked-failure recovery (§3.6). */ + checkedFailures: CheckedFailures | undefined, + environment: ExecutionEnvironment | undefined, +): Operation { + // Decided from source alone and shared with validation, completely, before a + // child is constructed: a malformed `` starts none of them. + const structure = allStructure(segment); + if (structure.violations.length > 0) { + for (const violation of structure.violations) { + owner.push(yield* raise(structuralErrorSegment(violation, segment))); + } + return; + } + + // Read once, here: every child starts from the same incoming snapshot, and + // reading it inside a child would let whichever ran first decide what the + // others saw. + const incoming = yield* env; + const children = structure.spawns.map( + (spawn) => () => + spawnChild( + spawn, + incoming, + parentMeta, + parentProps, + hideSet, + path, + checkedFailures, + environment, + ), + ); + + const scope = yield* useScope(); + const rendered = + scope.get(DurableContext) === undefined + ? yield* all(children.map((child) => child())) + : yield* durableAll(children.map((child) => (): Workflow => ephemeral(child()))); + + for (const text of rendered) { + if (text !== "") { + owner.push({ type: "text", content: text }); + } + } +} + function printErrorsPropError(segment: ComponentElement, message: string): ErrorSegment { return { type: "error", message: positioned(message, segment), source: "PrintErrors" }; } @@ -2392,7 +2578,10 @@ function* expandComponent( // answered: what canonical resolution selected here is what decides whether // this invocation is in one of this execution's identity domains, and nothing // on the answer or in the chain carries it (`invocation-identity.ts`). - const selection = environment?.componentIdentity?.beginImport(name); + // Opened under the scope this expansion is running in, which is what makes + // the frame this branch's own: a sibling `` resolving the same name at + // the same time opens its own, under its own scope. + const selection = environment?.componentIdentity?.beginImport(name, yield* useScope()); let selected: IdentityDomain | undefined; let dispatcher: FunctionComponent | undefined; /** diff --git a/packages/core/src/generated-xmd.ts b/packages/core/src/generated-xmd.ts index da91d105f..1ad68d9ba 100644 --- a/packages/core/src/generated-xmd.ts +++ b/packages/core/src/generated-xmd.ts @@ -134,6 +134,7 @@ import { RESERVED_STRUCTURAL } from "./structural.ts"; // The ordinary source rules, read rather than reimplemented: a construct means // one thing whether a person wrote it or an Agent did. import { + allStructure, answersViolations, answerViolations, breakViolations, @@ -2003,7 +2004,7 @@ function stated(segment: ComponentElement, scope: ReadonlySet): void { } /** The structural names that only their own parent may consume. */ -const CONSUMED_BY_PARENT: ReadonlySet = new Set(["Else", "Case", "Answer"]); +const CONSUMED_BY_PARENT: ReadonlySet = new Set(["Else", "Case", "Answer", "Spawn"]); /** * The structural names the generated root supplies no context for. @@ -2105,6 +2106,22 @@ function* structural( return; } + if (name === "All") { + const structure = allStructure(segment); + refuseStructure(structure.violations); + // Every child, before the fragment's first effect, and each from the + // bindings that reach the ``: the children run at the same time and + // merge nothing back, so none of them may be proved against a binding + // another one makes, and nothing any of them binds is visible afterwards. + // The lexical facts reset with the boundary, exactly as the shared rule + // above already refused a `` or `` that would cross it. + const incoming: ReadonlySet = new Set(scope); + for (const spawn of structure.spawns) { + yield* walk(spawn.element.children, table, ceilings, named, new Set(incoming), ROOT_LEXICAL); + } + return; + } + if (name === "PrintErrors") { refuseStructure(printErrorsViolations(segment)); yield* transparent(segment.children, table, ceilings, named, scope, lexical); diff --git a/packages/core/src/invocation-identity.ts b/packages/core/src/invocation-identity.ts index 884813fe0..696599812 100644 --- a/packages/core/src/invocation-identity.ts +++ b/packages/core/src/invocation-identity.ts @@ -391,17 +391,20 @@ export interface ProtectedDeclaration { */ export interface InvocationIdentities { /** - * Open the frame for one import the engine is about to ask for. + * Open the frame for one import the engine is about to ask for, under the + * engine scope that is asking. * * The engine settles it as soon as that import answers, whatever the answer - * was, so nothing a handler does in between decides what the frame holds. + * was, so nothing a handler does in between decides what the frame holds — + * including an import another branch opened while this one was in flight. */ - beginImport(name: string): ImportSelection; + beginImport(name: string, scope: Scope): ImportSelection; /** * Record what canonical resolution selected. Only core's own resolver calls - * this, from inside the import the frame above was opened for. + * this, from inside the import the frame above was opened for, and under the + * same engine scope that opened it. */ - select(name: string, definition: object, dispatcher?: unknown): void; + select(name: string, definition: object, scope: Scope): void; /** Answer for nothing, from here on. Called when the execution is torn down. */ revoke(): void; } @@ -414,7 +417,8 @@ export interface ImportSelection { * * Answers `undefined` unless exactly one canonical resolution happened inside * this frame, for the name the engine asked, selecting the implementation - * this execution built for that domain. + * this execution built for that domain. A selection made in another scope's + * frame is not one that happened inside this one. */ settle(): IdentityDomain | undefined; } @@ -1139,25 +1143,52 @@ export function installIdentities( } /** - * The import frames the engine has open, innermost last. + * The import frames each Effection scope has open, innermost last. + * + * A stack per scope rather than one for the execution. Nesting inside one + * scope is still LIFO — a handler may expand something of its own while an + * import is in flight, and the inner import owns the top until it closes. + * What a single execution-wide stack could not express is *branching*: two + * `` children may each have an import open at the same time, and + * whichever pushed last would then receive the other's canonical selection. + * One invocation would settle with no domain and the other with a domain it + * never selected, which is where an ordinary `` in each branch + * stopped being able to name its own durable identity. * - * A stack rather than a slot, because a handler may expand something of its - * own while an import is in flight. Anything that leaves two selections in - * one frame — a handler delegating twice, or two expansions interleaving — - * settles to nothing, which is the safe direction. + * The scope is a private key and nothing else. It is never published, never + * read from, and never reaches a document, a component or a handler; two + * frames belong together because they were opened under the same engine + * scope object, not because of anything either of them says. + * + * Anything that leaves two selections in one frame — a handler delegating + * twice — still settles to nothing, which is the safe direction. */ - const frames: { asked: string; selected: Minted | undefined; count: number }[] = []; + const frames = new Map(); return { identities: { - beginImport(asked: string): ImportSelection { + beginImport(asked: string, scope: Scope): ImportSelection { const frame = { asked, selected: undefined as Minted | undefined, count: 0 }; - frames.push(frame); + const open = frames.get(scope); + if (open === undefined) { + frames.set(scope, [frame]); + } else { + open.push(frame); + } return { settle(): IdentityDomain | undefined { - const index = frames.lastIndexOf(frame); - if (index >= 0) { - frames.splice(index, 1); + // Only this frame, and only from the scope that opened it: a + // sibling branch closing its own import may neither clear this one + // nor be cleared by it. + const stack = frames.get(scope); + if (stack !== undefined) { + const index = stack.lastIndexOf(frame); + if (index >= 0) { + stack.splice(index, 1); + } + if (stack.length === 0) { + frames.delete(scope); + } } return frame.count === 1 && frame.selected !== undefined ? frame.selected.domain @@ -1165,8 +1196,11 @@ export function installIdentities( }, }; }, - select(name: string, definition: FunctionComponentDefinition): void { - const frame = frames.at(-1); + select(name: string, definition: FunctionComponentDefinition, scope: Scope): void { + // The innermost import open in the scope that is resolving, which is + // the one this selection answers. A selection never reaches another + // branch's frame, however the two happen to interleave. + const frame = frames.get(scope)?.at(-1); if (frame === undefined) { return; } @@ -1185,6 +1219,10 @@ export function installIdentities( for (const domain of minted.values()) { domain.revoke(); } + // Every stack, not only the ones that emptied themselves: an execution + // torn down while a branch still had an import open leaves no frame + // behind for anything to select into. + frames.clear(); // The route goes with the domains: a wrapper projected into it, or a // route narrowed from it, answers for nothing once the execution that // minted the bodies is gone. diff --git a/packages/core/src/structural-rules.ts b/packages/core/src/structural-rules.ts index e343ad872..de6b9afde 100644 --- a/packages/core/src/structural-rules.ts +++ b/packages/core/src/structural-rules.ts @@ -716,6 +716,207 @@ export function switchStructure(segment: ComponentElement): SwitchStructure { return { violations, matching, ...(fallback === undefined ? {} : { fallback }) }; } +/** What a `` written outside the `` that runs it says. */ +export function straySpawnMessage(): string { + return ( + " must be a direct child of . is reserved: it never resolves a " + + "component, and only the it belongs to can run it." + ); +} + +/** What a `` written inside a spawned child says. */ +export function spawnReturnMessage(): string { + return ( + " cannot cross . A spawned child owns no value body, so a " + + "written inside one would have to select a value owned outside — which several " + + "children running at once may not race to claim. A component invoked inside the spawn " + + "still owns its own ." + ); +} + +/** What a `` written inside a spawned child with no loop of its own says. */ +export function spawnBreakMessage(): string { + return ( + " cannot cross . A spawned child cannot exit a written outside " + + ", because several children running at once may not race to decide one loop. A " + + " written wholly inside the spawn is broken by its own as usual." + ); +} + +/** + * One `` `` runs, and where it was written. + * + * `index` is the child index the element sits at, which is what its expansion + * frame is derived from (§5.6); `ordinal` is its place among the spawns, which + * is the order its durable child identity and its rendered output follow. + */ +export interface SpawnRegion { + readonly element: ComponentElement; + readonly index: number; + readonly ordinal: number; +} + +/** How an `` body divides into spawned children, and what it got wrong. */ +export interface AllStructure { + readonly violations: StructuralViolation[]; + /** The direct `` children, in authored order. */ + readonly spawns: SpawnRegion[]; +} + +/** Everything one `` element decides from what the author wrote. */ +function spawnElementViolations(segment: ComponentElement): StructuralViolation[] { + const found: StructuralViolation[] = []; + const names = authoredPropNames(segment); + if (names.length > 0) { + found.push( + violation( + "structural-usage-invalid", + "Spawn", + ` accepts no props. Got: "${names[0]}".`, + segment, + ), + ); + } + if (segment.selfClosing) { + found.push( + violation( + "structural-usage-invalid", + "Spawn", + " holds the markdown its child expands, so it is written paired: " + + "....", + segment, + ), + ); + } + return found; +} + +/** + * Every `` below an `` that is not one of its direct children. The + * walk stops at a nested ``, which owns the spawns beneath it. + */ +function misplacedSpawnViolations(children: Segment[]): StructuralViolation[] { + const found: StructuralViolation[] = []; + + const walk = (segments: Segment[], depth: number): void => { + for (const segment of segments) { + if (segment.type !== "component" || segment.name === "All") { + continue; + } + if (segment.name === "Spawn" && depth > 0) { + found.push(violation("structural-usage-invalid", "Spawn", straySpawnMessage(), segment)); + } + walk(segment.children, depth + 1); + } + }; + + walk(children, 0); + return found; +} + +/** + * What one spawned child's own body says about control flow leaving it. + * + * Lexical, like every other placement rule here: a `` is legal because a + * `` written inside the same spawn encloses it, and a `` has no + * owner to select at all, because `` produces no value and a spawn is not + * a value body. A definition invoked inside the child is its own source and is + * not reached from here, so its `` keeps its ordinary meaning. + * + * The walk stops at a nested ``, whose own structure owns the spawns + * beneath it, so one misplaced element is reported once. + */ +function spawnFlowViolations(spawn: ComponentElement): StructuralViolation[] { + const found: StructuralViolation[] = []; + + const walk = (segments: Segment[], insideLoop: boolean): void => { + for (const segment of segments) { + if (segment.type !== "component" || segment.name === "All") { + continue; + } + if (segment.name === "Return") { + found.push(violation("return-usage-invalid", "Return", spawnReturnMessage(), segment)); + continue; + } + if (segment.name === "Break" && !insideLoop) { + found.push(violation("structural-usage-invalid", "Break", spawnBreakMessage(), segment)); + continue; + } + walk(segment.children, insideLoop || segment.name === "Loop"); + } + }; + + walk(spawn.children, false); + return found; +} + +/** + * Divide an `` body into the children it runs and validate the division + * (spec §6.5). Everything here is read from source, before any child starts, so + * a malformed construct refuses the whole `` rather than being discovered + * once one child is already running. + * + * Two spawns is the smallest thing worth running at the same time: one alone is + * the sequential document it was already written as, and saying so is a fact + * about the source rather than a scheduling decision. + */ +export function allStructure(segment: ComponentElement): AllStructure { + const violations: StructuralViolation[] = []; + const spawns: SpawnRegion[] = []; + + const names = authoredPropNames(segment); + if (names.length > 0) { + violations.push( + violation("structural-usage-invalid", "All", ` accepts no props. Got: "${names[0]}".`), + ); + } + if (segment.selfClosing) { + violations.push( + violation( + "structural-usage-invalid", + "All", + " holds the children it runs, so it is written paired: " + + ".......", + ), + ); + } + + for (const [index, child] of segment.children.entries()) { + if (isBlankText(child)) { + continue; + } + if (child.type !== "component" || child.name !== "Spawn") { + violations.push( + violation( + "structural-usage-invalid", + "All", + ` holds only children. Found ${describeSegment(child)} directly inside ` + + "it.", + child.type === "component" ? child : undefined, + ), + ); + continue; + } + violations.push(...spawnElementViolations(child)); + violations.push(...spawnFlowViolations(child)); + spawns.push({ element: child, index, ordinal: spawns.length }); + } + + if (!segment.selfClosing && spawns.length < 2) { + violations.push( + violation( + "structural-usage-invalid", + "All", + " runs at least two children at the same time. Write the second one, " + + `or write the work inline. Found ${spawns.length}.`, + ), + ); + } + + violations.push(...misplacedSpawnViolations(segment.children)); + return { violations, spawns }; +} + const LOOP_PROPS = new Set(["max", "name"]); /** How a `` names itself in its own printed errors. */ diff --git a/packages/core/src/structural.ts b/packages/core/src/structural.ts index 5a375f3a7..1a295543e 100644 --- a/packages/core/src/structural.ts +++ b/packages/core/src/structural.ts @@ -143,6 +143,27 @@ export const STRUCTURAL_DECLARATIONS: readonly EngineStructuralDeclaration[] = [ as: null, context: null, }, + { + name: "All", + syntax: ["……"], + description: + "Run independent work at the same time. " + + "`firstsecond` waits for every spawned child, " + + "then renders their Markdown in authored order even when they finish in another order. " + + "Write at least two `` children directly inside it.", + as: null, + context: "The `` children this runs at the same time.", + }, + { + name: "Spawn", + syntax: ["…"], + description: + "Mark one child for an enclosing `` to run. Write `…` directly " + + "inside ``; bindings made in its content stay in that child, and its `` " + + "or `` cannot target work outside it.", + as: null, + context: "Markdown expanded in its own child, beside its siblings.", + }, { name: "PrintErrors", syntax: ["…"], diff --git a/packages/core/tests/all.test.ts b/packages/core/tests/all.test.ts new file mode 100644 index 000000000..5016255bf --- /dev/null +++ b/packages/core/tests/all.test.ts @@ -0,0 +1,1489 @@ +/** + * Tier ALL — spawned document work running at the same time + * (spec §6.5 `` and ``). + * + * Every case here drives the ordinary scanner, the structural rules, the + * expansion engine and the durable stream. Concurrency is established with + * signals the children and the journal publish — never with a sleep — and the + * releases are ordered so that the child which finishes *second* is the one the + * document renders *first*. Calling the durable substrate directly would prove + * the substrate rather than the language, so nothing here does. + * + * Each test names the defect it kills: expanding the children in sequence, + * emitting them in completion order, running them on the parent coroutine, + * sharing one block counter, sharing the binding environment, leaving a held + * sibling alive after a failure, publishing one child's output before the join, + * and letting a `` or `` claim an owner outside the spawn. + */ + +import { beforeAll, describe, it } from "@executablemd/test-support/bdd"; +import { expect } from "@executablemd/test-support/expect"; +import { race, resource, scoped, sleep, spawn, withResolvers } from "effection"; +import type { Operation } from "effection"; +import { createDurableOperation, ephemeral, InMemoryStream } from "@executablemd/durable-streams"; +import type { + DurableEvent, + EffectDescription, + Json, + Workflow, +} from "@executablemd/durable-streams"; +import { useHostFiles } from "@executablemd/runtime"; +import { useEchoExec, useStubFs } from "@executablemd/runtime/test"; +import { execute } from "../src/execute.ts"; +import { executeInstalled } from "../host.ts"; +import { evaluateGeneratedXmd, pinnedComponent } from "../host.ts"; +import type { + DurablePreparation, + ExecutionInstallation, + GeneratedObservation, + GeneratedXmdRequest, + RetainedFragmentIdentity, +} from "../host.ts"; +import { forEach } from "@effectionx/stream-helpers"; +import { collect } from "../src/collect.ts"; +import { retain } from "../src/component-api.ts"; +import { getExpansion } from "../src/expansion.ts"; +import { retainedSource } from "../src/root-source.ts"; +import { registerComponents } from "../src/components/registration.ts"; +import { Agent } from "../src/agent/agent-api.ts"; +import type { AgentPromptEvent } from "../src/agent/agent-api.ts"; +import { agentIdentityComponents, installAgentComponents } from "../src/agent/components.ts"; +import { useTempFileCompiler } from "../src/temp-file-compiler.ts"; +import { inspectSyntax } from "../src/inspect.ts"; +import { RESERVED_STRUCTURAL } from "../src/structural.ts"; +import { validateDocument } from "../src/document-validation.ts"; +import { inlineSource } from "../src/root-source.ts"; +import type { FunctionComponentDefinition, JsonObject } from "../src/types.ts"; + +const NO_PROPS = { type: "object", properties: {}, additionalProperties: false }; +const NAMED = { + type: "object", + properties: { name: { type: "string" } }, + required: ["name"], + additionalProperties: false, +}; + +/** + * How long a signal that a correct engine publishes immediately may go + * unpublished before the wait is called a deadlock. + * + * Never reached by a passing run: every barrier below is opened by the children + * themselves or by the journal, so this bounds only the failure mode. A + * sequential expansion would otherwise hold its first child at a barrier its + * sibling can no longer reach, and the suite would hang instead of saying what + * went wrong. + */ +const DEADLOCK_MS = 10_000; + +/** A one-shot signal two operations coordinate through. */ +interface Signal { + publish(): void; + readonly published: Operation; +} + +function signal(): Signal { + const resolvers = withResolvers(); + let settled = false; + return { + publish() { + if (!settled) { + settled = true; + resolvers.resolve(true); + } + }, + get published() { + return resolvers.operation; + }, + }; +} + +/** Wait for a signal, reporting a deadlock rather than hanging on one. */ +function* awaiting(what: string, waited: Operation): Operation { + const reached = yield* race([ + waited, + (function* (): Operation { + yield* sleep(DEADLOCK_MS); + return false; + })(), + ]); + if (!reached) { + throw new Error(`${what} never happened: the spawned children did not run at the same time`); + } +} + +/** + * The gates, tripwires and timelines one document's registered components + * share. + * + * Three facts about one child are kept apart on purpose: that it reached its + * barrier, that it was let go, and that its own durable record landed. A + * driver that could only see the last of them could not tell a document whose + * children ran together from one whose children ran in turn. + */ +class Harness { + /** Every `` and `` that reached its barrier, in arrival order. */ + readonly arrived: string[] = []; + /** Every registered component invocation, in order. */ + readonly ran: string[] = []; + /** The expansion identifier each `` saw, by its name. */ + readonly identities = new Map(); + /** `start:`/`stop:` marks the retained resources published. */ + readonly timeline: string[] = []; + /** What each `` saw of a retained resource. */ + readonly observed: string[] = []; + + readonly #arrivals = new Map(); + readonly #releases = new Map(); + readonly #records = new Map(); + + static #slot(map: Map, name: string): Signal { + const existing = map.get(name); + if (existing !== undefined) { + return existing; + } + const created = signal(); + map.set(name, created); + return created; + } + + announce(name: string): void { + this.arrived.push(name); + Harness.#slot(this.#arrivals, name).publish(); + } + + held(name: string): Operation { + return awaiting(`<${name}> being released`, Harness.#slot(this.#releases, name).published); + } + + recorded(name: string): void { + Harness.#slot(this.#records, name).publish(); + } + + arrival(name: string): Operation { + return awaiting(`${name} arriving`, Harness.#slot(this.#arrivals, name).published); + } + + append(name: string): Operation { + return awaiting(`${name} recording its work`, Harness.#slot(this.#records, name).published); + } + + release(name: string): void { + Harness.#slot(this.#releases, name).publish(); + } +} + +function harness(): Harness { + return new Harness(); +} + +type Gated = Harness; + +/** Append one entry to the journal, the way any durable operation does. */ +function* mark(description: EffectDescription, value: Json): Workflow { + return yield createDurableOperation(description, function* () { + return value; + }); +} + +/** A resource whose start and stop are both on the record. */ +function useWatch(timeline: string[], label: string): Operation { + return resource(function* (provide) { + timeline.push(`start:${label}`); + try { + yield* provide(`held:${label}`); + } finally { + timeline.push(`stop:${label}`); + } + }); +} + +/** + * The components every document below is written against. + * + * `` is the barrier: it announces that it is live, waits to be released, + * and only then appends its own durable record — so which child reached the + * document first, which was released first and which appended first are three + * separately observable facts. + */ +function* useComponents(shared: Gated): Operation { + yield* registerComponents([ + { + name: "Gate", + origin: "tier-all", + props: NAMED, + *fn(props) { + const name = String(props.name); + shared.ran.push(`gate:${name}`); + shared.announce(name); + yield* shared.held(name); + yield* mark({ type: "gate", name: `gate:${name}` }, name); + shared.recorded(name); + return `[${name}]`; + }, + }, + { + name: "Probe", + origin: "tier-all", + props: NAMED, + *fn(props) { + const name = String(props.name); + shared.ran.push(`probe:${name}`); + shared.identities.set(name, (yield* getExpansion()).id); + return `(${name})`; + }, + }, + { + name: "Keep", + origin: "tier-all", + props: NAMED, + *fn(props) { + const name = String(props.name); + shared.ran.push(`keep:${name}`); + return yield* retain(() => useWatch(shared.timeline, name)); + }, + }, + { + name: "Observe", + origin: "tier-all", + props: NAMED, + // deno-lint-ignore require-yield + *fn(props) { + const name = String(props.name); + shared.observed.push( + `${name}:${shared.timeline.includes("stop:kept") ? "released" : "live"}`, + ); + return ""; + }, + }, + { + name: "Fail", + origin: "tier-all", + props: NAMED, + *fn(props) { + const name = String(props.name); + shared.ran.push(`fail:${name}`); + shared.announce(name); + yield* shared.held(name); + throw new Error(`FAILED:${name}`); + }, + }, + ]); +} + +/** What one document run produced. */ +interface Run { + readonly ok: boolean; + readonly output: string; + readonly failure: string; + readonly events: DurableEvent[]; +} + +/** + * Run one document to completion, with the gate components registered and a + * driver task free to open the barriers while the run is still live. + */ +function run( + source: string, + options: { + shared?: Gated; + stream?: InMemoryStream; + files?: Record; + drive?: (shared: Gated, stream: InMemoryStream) => Operation; + } = {}, +): Operation { + return scoped(function* () { + const shared = options.shared ?? harness(); + const stream = options.stream ?? new InMemoryStream(); + yield* useHostFiles(); + yield* useStubFs({ "test.md": source, ...options.files }); + yield* useEchoExec(); + yield* useComponents(shared); + if (options.drive) { + yield* spawn(() => options.drive!(shared, stream)); + } + // Drained chunk by chunk rather than collected: a run that fails still + // emitted whatever it emitted, and a test asking whether `` published + // a child early has to be able to see it. + const chunks: string[] = []; + const result = yield* scoped(function* () { + const execution = yield* execute({ path: "test.md", stream }); + try { + yield* forEach(function* (chunk: string) { + chunks.push(chunk); + }, execution.output); + } catch { + // The execution's own outcome below says why the stream stopped. + } + return yield* execution; + }); + return { + ok: result.ok, + output: chunks.join(""), + failure: result.ok ? "" : result.error.message, + events: stream.snapshot(), + }; + }); +} + +/** The name one durable record settled with, or `undefined` for anything else. */ +function recordedName(event: DurableEvent): string | undefined { + if (event.type !== "yield" || event.description.type !== "gate") { + return undefined; + } + return event.result.status === "ok" ? String(event.result.value ?? "") : undefined; +} + +/** Every durable record one gate appended, in journal order. */ +function gateOrder(events: DurableEvent[]): string[] { + const found: string[] = []; + for (const event of events) { + const name = recordedName(event); + if (name !== undefined) { + found.push(name); + } + } + return found; +} + +/** The coroutine each gate record was written under, by gate name. */ +function gateCoroutines(events: DurableEvent[]): Map { + const found = new Map(); + for (const event of events) { + const name = recordedName(event); + if (name !== undefined) { + found.set(name, event.coroutineId); + } + } + return found; +} + +interface EvalEntry { + readonly name: string; + readonly coroutineId: string; +} + +function evalEntries(events: DurableEvent[]): EvalEntry[] { + return events + .filter((event) => event.type === "yield" && event.description.type === "eval") + .map((event) => ({ + name: event.type === "yield" ? event.description.name : "", + coroutineId: event.coroutineId, + })); +} + +/** Every coroutine this run closed, with the status it closed under. */ +function closes(events: DurableEvent[]): Array<{ id: string; status: string }> { + return events + .filter((event) => event.type === "close") + .map((event) => ({ id: event.coroutineId, status: event.result.status })); +} + +/** The value each closed child coroutine settled with, in journal order. */ +function childCloseValues(events: DurableEvent[]): Array<[string, Json]> { + const found: Array<[string, Json]> = []; + for (const event of events) { + if (event.type === "close" && event.coroutineId.includes(".") && event.result.status === "ok") { + found.push([event.coroutineId, event.result.value ?? null]); + } + } + return found; +} + +const TWO_GATES = [ + "", + '', + '', + "", +].join("\n"); + +describe("Tier ALL — PA1: both children are live, and output follows the source", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL1: releasing the second child first appends it first and renders it second", function* () { + const result = yield* run(TWO_GATES, { + *drive(shared) { + // Both children have to be live at once before either is released: + // a sequential expansion can never satisfy this, because the second + // child would not start until the first had finished. + yield* shared.arrival("one"); + yield* shared.arrival("two"); + expect(shared.arrived).toEqual(["one", "two"]); + shared.release("two"); + yield* shared.append("two"); + shared.release("one"); + }, + }); + + expect(result.ok).toBe(true); + // Completion order decided the journal; it did not decide the document. + expect(gateOrder(result.events)).toEqual(["two", "one"]); + expect(result.output).toContain("[one][two]"); + expect(result.output).not.toContain("[two][one]"); + }); + + it("ALL2: no child output is published before the join succeeds", function* () { + const emitted: string[] = []; + const result = yield* run(TWO_GATES, { + *drive(shared, stream) { + stream.onAppend = (event) => { + const name = recordedName(event); + if (name !== undefined) { + // What the document has emitted at the moment one child's own + // durable work lands: nothing of either child's, because the join + // has not returned. + emitted.push(`append:${name}`); + } + }; + yield* shared.arrival("one"); + yield* shared.arrival("two"); + shared.release("two"); + shared.release("one"); + }, + }); + + expect(result.ok).toBe(true); + expect(emitted).toHaveLength(2); + expect(result.output).toContain("[one][two]"); + }); +}); + +describe("Tier ALL — PA2: durable identity follows the source", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL3: children close on source-ordered coroutines under the one that reached ", function* () { + const result = yield* run(TWO_GATES, { + *drive(shared) { + yield* shared.arrival("one"); + yield* shared.arrival("two"); + shared.release("two"); + yield* shared.append("two"); + shared.release("one"); + }, + }); + + expect(result.ok).toBe(true); + const coroutines = gateCoroutines(result.events); + // Source order, not completion order: "two" finished first and is still + // the second child. + expect(coroutines.get("one")).toBe("root.0"); + expect(coroutines.get("two")).toBe("root.1"); + expect(closes(result.events)).toEqual([ + { id: "root.1", status: "ok" }, + { id: "root.0", status: "ok" }, + { id: "root", status: "ok" }, + ]); + // Each child closes with exactly the markdown it rendered. + expect(new Map(childCloseValues(result.events))).toEqual( + new Map([ + ["root.1", "[two]"], + ["root.0", "[one]"], + ]), + ); + }); + + it("ALL4: nesting produces hierarchical child identities", function* () { + const result = yield* run( + [ + "", + "", + "", + '', + '', + "", + "", + '', + "", + ].join("\n"), + { + *drive(shared) { + yield* shared.arrival("inner-a"); + yield* shared.arrival("inner-b"); + yield* shared.arrival("outer"); + shared.release("inner-a"); + shared.release("inner-b"); + shared.release("outer"); + }, + }, + ); + + expect(result.ok).toBe(true); + const coroutines = gateCoroutines(result.events); + expect(coroutines.get("inner-a")).toBe("root.0.0"); + expect(coroutines.get("inner-b")).toBe("root.0.1"); + expect(coroutines.get("outer")).toBe("root.1"); + }); + + it("ALL5: a complete replay runs no spawned work at all", function* () { + const stream = new InMemoryStream(); + const live = harness(); + const first = yield* run(TWO_GATES, { + shared: live, + stream, + *drive(shared) { + yield* shared.arrival("one"); + yield* shared.arrival("two"); + shared.release("two"); + shared.release("one"); + }, + }); + expect(first.ok).toBe(true); + expect(live.ran).toEqual(["gate:one", "gate:two"]); + + const replayed = yield* run(TWO_GATES, { stream: new InMemoryStream(first.events) }); + expect(replayed.ok).toBe(true); + expect(replayed.output).toBe(first.output); + // Nothing spawned ran, so no barrier had to be opened for the replay. + expect(gateOrder(replayed.events)).toEqual(gateOrder(first.events)); + }); +}); + +const COUNTER_DOC = [ + "```js eval", + "output('BEFORE');", + "```", + "", + "", + "", + "", + "```js eval", + "output('S1');", + "```", + "", + '', + "", + "", + "", + "", + "```js eval", + "output('S2');", + "```", + "", + '', + "", + "", + "", + "", + "```js eval", + "output('AFTER');", + "```", +].join("\n"); + +describe("Tier ALL — PA3: counters, paths and the parent's own numbering", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL6: children reuse local block ids, and later parent work keeps its own", function* () { + const shared = harness(); + const result = yield* run(COUNTER_DOC, { shared }); + + expect(result.ok).toBe(true); + const entries = evalEntries(result.events); + const onParent = entries.filter((entry) => entry.coroutineId === "root"); + // The parent's counter never saw the children: the block after `` is + // numbered as though no child had run. + expect(onParent.map((entry) => entry.name)).toEqual(["eval:eval:root:0", "eval:eval:root:1"]); + + const inChildren = entries.filter((entry) => entry.coroutineId !== "root"); + expect(inChildren.map((entry) => entry.coroutineId).toSorted()).toEqual(["root.0", "root.1"]); + // Both children number their own first block the same way and collide with + // nothing, because the child coroutine namespaces it. + expect(new Set(inChildren.map((entry) => entry.name))).toEqual(new Set(["eval:eval:root:0"])); + + // Two spawns, two stable and distinct expansion identities. + const p1 = shared.identities.get("p1"); + const p2 = shared.identities.get("p2"); + expect(typeof p1).toBe("string"); + expect(typeof p2).toBe("string"); + expect(p1).not.toBe(p2); + + // A second run of the same document derives all three again. + const again = harness(); + const rerun = yield* run(COUNTER_DOC, { shared: again }); + expect(rerun.ok).toBe(true); + expect(again.identities.get("p1")).toBe(p1); + expect(again.identities.get("p2")).toBe(p2); + // The same identities on the same coroutines. Compared as a set, because + // which child appends first is exactly what scheduling is allowed to + // decide — the contract fixes what a block is called and where, never the + // order two independent children reach the journal. + const identify = (found: EvalEntry[]): string[] => + found.map((entry) => `${entry.coroutineId}/${entry.name}`).toSorted(); + expect(identify(evalEntries(rerun.events))).toEqual(identify(entries)); + + // And a replay reproduces the rendering without running any of it. + const idle = harness(); + const replayed = yield* run(COUNTER_DOC, { + shared: idle, + stream: new InMemoryStream(result.events), + }); + expect(replayed.output).toBe(result.output); + expect(idle.ran).toEqual([]); + }); +}); + +const ISOLATION_DOC = [ + "", + "", + 'chosen', + '', + "spawn1({picked}/{handle})", + "", + "", + "spawn2({picked}/{handle})", + "", + "", + "", + "after({picked}/{handle})", + "", + '', +].join("\n"); + +describe("Tier ALL — PA4: a child's bindings and resources are its own", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL7: a binding and a retained resource live on in their child and nowhere else", function* () { + const shared = harness(); + const result = yield* run(ISOLATION_DOC, { shared }); + + expect(result.ok).toBe(true); + // Later work in the same child reads both. + expect(result.output).toContain("spawn1(chosen/held:kept)"); + // The sibling and the work after `` read neither: the names are not + // bound there, so they render as the text that was written. + expect(result.output).toContain("spawn2({picked}/{handle})"); + expect(result.output).toContain("after({picked}/{handle})"); + // The resource lived while the child did, and was released when it ended. + expect(shared.timeline).toEqual(["start:kept", "stop:kept"]); + expect(shared.observed).toEqual(["after:released"]); + }); +}); + +describe("Tier ALL — PA5: a partial replay restores one child and resumes the other", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL8: the completed child is restored and only the unrecorded child runs", function* () { + const stream = new InMemoryStream(); + const live = harness(); + const golden = yield* run(TWO_GATES, { + shared: live, + stream, + *drive(shared, journal) { + const closedOne = signal(); + journal.onAppend = (event) => { + if (event.type === "close" && event.coroutineId === "root.0") { + closedOne.publish(); + } + }; + yield* shared.arrival("one"); + yield* shared.arrival("two"); + // The first child is released and allowed to close before the second + // records anything, so the truncation below has exactly one complete + // child and one that has not started its work. + shared.release("one"); + yield* awaiting("the first child closing", closedOne.published); + shared.release("two"); + }, + }); + expect(golden.ok).toBe(true); + expect(golden.output).toContain("[one][two]"); + + const events = golden.events; + const closedAt = events.findIndex( + (event) => event.type === "close" && event.coroutineId === "root.0", + ); + expect(closedAt).toBeGreaterThan(0); + const partial = events.slice(0, closedAt + 1); + expect(partial.some((event) => event.type === "close" && event.coroutineId === "root.1")).toBe( + false, + ); + expect(gateOrder(partial)).toEqual(["one"]); + + const resumed = harness(); + const replayed = yield* run(TWO_GATES, { + shared: resumed, + stream: new InMemoryStream(partial), + *drive(shared) { + yield* shared.arrival("two"); + shared.release("two"); + }, + }); + + expect(replayed.ok).toBe(true); + // The completed child's rendering came back from its recorded close, and + // only the child with no close ran. + expect(replayed.output).toBe(golden.output); + expect(resumed.ran).toEqual(["gate:two"]); + expect(gateCoroutines(replayed.events).get("two")).toBe("root.1"); + }); +}); + +describe("Tier ALL — PA6: a failure cancels its siblings and publishes nothing", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL9: a held sibling is cancelled and joined, and renders nothing", function* () { + const shared = harness(); + const result = yield* run( + [ + "", + '', + '', + "", + "", + "tail", + ].join("\n"), + { + shared, + *drive(inner) { + yield* inner.arrival("bad"); + yield* inner.arrival("held"); + // The sibling is still holding at its barrier when the first child + // fails, and is never released by this driver. + inner.release("bad"); + }, + }, + ); + + expect(result.ok).toBe(false); + expect(result.failure).toContain("FAILED:bad"); + // Neither child's private buffer reached the document, and nothing after + // `` ran. + expect(result.output).not.toContain("[held]"); + expect(result.output).not.toContain("tail"); + // The held sibling's scope was torn down as part of the join. + expect(shared.timeline).toEqual(["start:kept", "stop:kept"]); + // The journal holds only what was acknowledged: the failing child closed + // with its error, the cancelled one as cancelled, and the held gate never + // recorded work it did not do. + expect(gateOrder(result.events)).toEqual([]); + const closed = new Map(closes(result.events).map((entry) => [entry.id, entry.status])); + expect(closed.get("root.0")).toBe("err"); + expect(closed.get("root.1")).toBe("cancelled"); + }); + + it("ALL9b: a child that already succeeded publishes nothing when a sibling fails", function* () { + const shared = harness(); + const result = yield* run( + [ + "", + '', + '', + "", + "", + "tail", + ].join("\n"), + { + shared, + *drive(inner) { + yield* inner.arrival("done"); + yield* inner.arrival("bad"); + // The first child runs to completion, and only then does its sibling + // fail: its rendering exists, and the join is what decides whether + // the document ever sees it. + inner.release("done"); + yield* inner.append("done"); + inner.release("bad"); + }, + }, + ); + + expect(result.ok).toBe(false); + expect(result.failure).toContain("FAILED:bad"); + // The successful child's own markdown was never published: the join failed, + // so `` emitted none of it. + expect(result.output).not.toContain("[done]"); + expect(result.output).not.toContain("tail"); + // Its durable record stands, because the journal only ever held work that + // was acknowledged. + expect(gateOrder(result.events)).toEqual(["done"]); + expect(shared.timeline).toEqual(["start:kept", "stop:kept"]); + const closed = new Map(closes(result.events).map((entry) => [entry.id, entry.status])); + expect(closed.get("root.0")).toBe("ok"); + expect(closed.get("root.1")).toBe("err"); + }); + + it("ALL10: cancelling the document leaves no spawned work alive", function* () { + const shared = harness(); + const stream = new InMemoryStream(); + const outcome = yield* scoped(function* () { + yield* useHostFiles(); + yield* useStubFs({ + "test.md": [ + "", + '', + '', + "", + ].join("\n"), + }); + yield* useEchoExec(); + yield* useComponents(shared); + return yield* race([ + (function* (): Operation { + const execution = yield* execute({ path: "test.md", stream }); + yield* collect(execution); + return "finished"; + })(), + (function* (): Operation { + yield* shared.arrival("one"); + yield* shared.arrival("two"); + return "cancelled"; + })(), + ]); + }); + + expect(outcome).toBe("cancelled"); + // The scope exited while both children were held, and both were joined: + // the retained resource is released and no gate recorded work. + expect(shared.timeline).toEqual(["start:kept", "stop:kept"]); + expect(gateOrder(stream.snapshot())).toEqual([]); + }); +}); + +describe("Tier ALL — PA7: malformed structure refuses before any child starts", () => { + beforeAll(() => useTempFileCompiler()); + + const cases: Array<[string, string, string]> = [ + [ + "ALL11: fewer than two spawns", + ["", '', ""].join("\n"), + "at least two ", + ], + [ + "ALL12: a prop on ", + [ + "", + '', + '', + "", + ].join("\n"), + " accepts no props", + ], + ["ALL13: a self-closing ", "", "written paired"], + [ + "ALL14: a self-closing ", + ["", "", '', ""].join("\n"), + " holds the markdown", + ], + [ + "ALL15: a prop on ", + [ + "", + '', + '', + "", + ].join("\n"), + " accepts no props", + ], + [ + "ALL16: substantive direct text", + [ + "", + "stray words", + '', + '', + "", + ].join("\n"), + " holds only children", + ], + [ + "ALL17: a direct component child", + [ + "", + '', + '', + '', + "", + ].join("\n"), + " holds only children", + ], + [ + "ALL18: a with no ", + '', + "direct child of ", + ], + [ + "ALL19: a below its rather than directly inside it", + [ + "", + '', + '', + "", + ].join("\n"), + "direct child of ", + ], + ]; + + for (const [title, source, expected] of cases) { + it(title, function* () { + const shared = harness(); + const result = yield* run(source, { shared }); + expect(result.ok).toBe(false); + expect(result.failure).toContain(expected); + // No tripwire in any child ran: the refusal is decided from source + // before a child is constructed. + expect(shared.ran).toEqual([]); + }); + } + + it("ALL20: a repository file cannot supply or ", function* () { + const shared = harness(); + const result = yield* run("from a file", { + shared, + files: { "components/Spawn.md": "a repository spawn\n" }, + }); + expect(result.output).not.toContain("a repository spawn"); + expect(result.failure).toContain("never resolves a component"); + expect(shared.ran).toEqual([]); + }); +}); + +describe("Tier ALL — PA8: and cannot cross a spawn", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL21: a in a spawn cannot exit a loop outside ", function* () { + const shared = harness(); + const result = yield* run( + [ + "", + "", + "", + '', + "", + "", + ].join("\n"), + { shared }, + ); + expect(result.ok).toBe(false); + expect(result.failure).toContain(" cannot cross "); + expect(shared.ran).toEqual([]); + }); + + it("ALL22: a loop wholly inside a spawn is broken by its own ", function* () { + const result = yield* run( + [ + "", + "a", + "b", + "", + ].join("\n"), + ); + expect(result.ok).toBe(true); + expect(result.output).toContain("ab"); + expect(result.output).not.toContain("ERROR"); + }); + + it("ALL23: a in a spawn satisfies no value root", function* () { + const result = yield* run( + [ + "---", + "returns:", + " type: string", + "---", + "", + "", + '', + "b", + "", + ].join("\n"), + ); + expect(result.ok).toBe(false); + // The body still owes its own ``: the one inside the spawn neither + // satisfies the declaration nor stands in for it. + expect(result.failure).toContain("no "); + }); + + it("ALL24: a value component invoked inside a spawn keeps its own ", function* () { + const result = yield* run( + [ + "", + 'got {picked}', + "b", + "", + ].join("\n"), + { + files: { + "components/Answerer.md": [ + "---", + "returns:", + " type: string", + "---", + "", + '', + ].join("\n"), + }, + }, + ); + expect(result.ok).toBe(true); + expect(result.output).toContain("got an answer"); + expect(result.output).toContain("b"); + }); + + it("ALL25: non-executing validation reports both boundaries where they were written", function* () { + const shared = harness(); + const source = [ + "", + "", + "", + '', + "", + "", + ].join("\n"); + yield* useComponents(shared); + const validation = yield* validateDocument(inlineSource(source)); + const messages = validation.diagnostics.map((diagnostic) => diagnostic.message); + expect(messages.some((message) => message.includes(" cannot cross "))).toBe(true); + expect(messages.some((message) => message.includes(" cannot cross "))).toBe( + true, + ); + // One mistake, one diagnostic: the stray-element sentences are not also + // reported for the same two elements. + expect(messages.some((message) => message.includes("must be written inside a "))).toBe( + false, + ); + }); +}); + +const GENERATED_ROOT = "workflows/agent.md"; +const GENERATED_SOURCE = "The host ran a generated fragment.\n"; + +function hostIdentity(origin: string, key: string): RetainedFragmentIdentity { + return { kind: "component-answer", origin, key, revision: "1" }; +} + +const GENERATED_PROBE: FunctionComponentDefinition = { + kind: "function", + name: "Probe", + props: NO_PROPS, + // deno-lint-ignore require-yield + *fn() { + return "probed"; + }, +}; + +function generatedProbe(): GeneratedObservation { + return pinnedComponent("Probe", hostIdentity("test://probe", "Probe"), GENERATED_PROBE); +} + +function generatedRequest(source: string): GeneratedXmdRequest { + return { + id: "turn-1", + source, + workspaceRoots: ["workspace://primary"], + selectedRoot: "workspace://primary", + observations: [generatedProbe()], + }; +} + +interface Attempt { + readonly output?: string; + readonly failure?: string; + readonly events: DurableEvent[]; +} + +function evaluateFragment(source: string): Operation { + return scoped(function* () { + const stream = new InMemoryStream(); + const captured: { result?: string } = {}; + // A preparation yields durable effects, and the evaluator is an ordinary + // operation whose *own* effects identify themselves against the durable + // root they run in. `ephemeral()` is the bridge for exactly that: the + // wrapper writes no journal entry of its own, and the evaluator's + // admission record still lands under the root coroutine. + const prepare: DurablePreparation = function* () { + captured.result = yield* ephemeral(evaluateGeneratedXmd(generatedRequest(source))); + }; + const installation: ExecutionInstallation = { prepare }; + const execution = yield* executeInstalled( + { ...retainedSource(GENERATED_ROOT, GENERATED_SOURCE), stream, includes: [] }, + [installation], + ); + const result = yield* execution; + const events = stream.snapshot(); + return result.ok + ? { output: captured.result ?? "", events } + : { failure: result.error.message, events }; + }); +} + +/** What each generated-XMD admission decided. */ +function decisions(events: DurableEvent[]): string[] { + const found: string[] = []; + for (const event of events) { + if ( + event.type !== "yield" || + event.description.type !== "generated_xmd" || + event.result.status !== "ok" + ) { + continue; + } + const value = event.result.value; + if (typeof value === "object" && value !== null && !Array.isArray(value)) { + const record: JsonObject = value; + found.push(typeof record.decision === "string" ? record.decision : ""); + } + } + return found; +} + +describe("Tier ALL — PA9: the construct exists everywhere the language does", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL26: the canonical syntax surface lists both names as structural", function* () { + const catalog = yield* inspectSyntax({ includes: [] }); + const names = catalog.categories[0].entries.map((entry) => entry.name); + expect(names).toContain("All"); + expect(names).toContain("Spawn"); + expect(RESERVED_STRUCTURAL.has("All")).toBe(true); + expect(RESERVED_STRUCTURAL.has("Spawn")).toBe(true); + }); + + it("ALL27: admitted generated XMD runs a valid ", function* () { + const attempt = yield* evaluateFragment( + ["", "", "", ""].join("\n"), + ); + expect(attempt.failure).toBe(undefined); + expect(attempt.output).toContain("probed"); + expect(decisions(attempt.events)).toEqual(["admitted"]); + }); + + it("ALL28: a malformed refuses the fragment before its first effect", function* () { + const attempt = yield* evaluateFragment( + ["", "", ""].join("\n"), + ); + expect(decisions(attempt.events)).toEqual(["refused"]); + expect(attempt.output ?? "").not.toContain("probed"); + }); + + it("ALL29: a stray refuses the fragment", function* () { + const attempt = yield* evaluateFragment("\n"); + expect(decisions(attempt.events)).toEqual(["refused"]); + expect(attempt.output ?? "").not.toContain("probed"); + }); +}); + +/** + * Tier PA10a/c — the Story's own example: ordinary `` in each branch. + * + * `` is a capability-backed identity component, so two of them running + * at once is the case where canonical resolution has to attribute each answer + * and each selection to the exact import that opened it. These rows drive the + * real components over a real journal; nothing here stands in for ``. + */ + +/** One conversation the stubbed provider holds, and how it is let go. */ +interface Conversation { + /** Session keys that reached the provider, in arrival order. */ + readonly arrived: string[]; + /** Whether a provider factory was materialized, and how often. */ + activations: () => number; + /** How many implementations the declared `` factory built. */ + sessions: () => number; + reached(sessionKey: string): Operation; + release(sessionKey: string): void; + readonly installation: ExecutionInstallation; + readonly declaration: ExecutionInstallation; +} + +function conversations(options: { gated?: boolean } = {}): Conversation { + const arrived: string[] = []; + const arrivals = new Map(); + const releases = new Map(); + const slot = (map: Map, key: string): Signal => { + const existing = map.get(key); + if (existing !== undefined) { + return existing; + } + const created = signal(); + map.set(key, created); + return created; + }; + let activations = 0; + let built = 0; + + const declared = agentIdentityComponents().map((component) => ({ + ...component, + factory: (claim: Parameters[0]) => { + // One implementation per declared component per execution, however many + // branches invoke it. A domain minted per `` would show up here. + built += 1; + return component.factory(claim); + }, + })); + + return { + arrived, + activations: () => activations, + sessions: () => built, + reached(sessionKey: string) { + return awaiting(`${sessionKey} reaching the provider`, slot(arrivals, sessionKey).published); + }, + release(sessionKey: string) { + slot(releases, sessionKey).publish(); + }, + declaration: { components: declared }, + installation: { + *install(): Operation { + yield* installAgentComponents({ + defaultAgent: "stub-agent", + rootProvider: { + options: { defaultAgent: "stub-agent", permissionMode: "deny-all" }, + factory: function* () { + activations += 1; + yield* Agent.around( + { + // deno-lint-ignore require-yield + *agent([name]) { + return name ?? "stub-agent"; + }, + // deno-lint-ignore require-yield + *session([routed]) { + const name = typeof routed === "string" ? routed : routed?.name; + return { sessionKey: `stub:${name ?? "default"}`, cwd: "/stub" }; + }, + // deno-lint-ignore require-yield + *prompt([_content, promptOptions]) { + const session = promptOptions?.session; + const key = + typeof session === "object" && session !== null && "sessionKey" in session + ? String(session.sessionKey) + : "stub:default"; + return { + *[Symbol.iterator]() { + arrived.push(key); + slot(arrivals, key).publish(); + if (options.gated === true) { + yield* awaiting(`${key} being released`, slot(releases, key).published); + } + // Declared as the events they are, rather than as + // literals narrowed at the return: the provider's own + // vocabulary is what a turn produces. + const turn: AgentPromptEvent[] = [ + { + type: "started", + agent: "stub-agent", + session: { sessionKey: key, cwd: "/stub" }, + }, + { type: "text_delta", text: `[${key}]` }, + { type: "terminal", status: "completed" }, + ]; + let stage = 0; + return { + // deno-lint-ignore require-yield + *next() { + const event = turn[stage]; + if (event === undefined) { + return { done: true, value: `[${key}]` }; + } + stage += 1; + return { done: false, value: event }; + }, + }; + }, + }; + }, + }, + { at: "min" }, + ); + }, + }, + }); + }, + }, + }; +} + +/** What one Session document produced. */ +interface Talked { + readonly ok: boolean; + readonly failure: string; + readonly output: string; + readonly events: DurableEvent[]; +} + +function talking( + source: string, + held: Conversation, + options: { stream?: InMemoryStream; drive?: () => Operation } = {}, +): Operation { + return scoped(function* () { + const stream = options.stream ?? new InMemoryStream(); + if (options.drive) { + yield* spawn(options.drive); + } + const chunks: string[] = []; + const result = yield* scoped(function* () { + const execution = yield* executeInstalled({ ...inlineSource(source), stream }, [ + held.declaration, + held.installation, + ]); + try { + yield* forEach(function* (chunk: string) { + chunks.push(chunk); + }, execution.output); + } catch { + // The outcome below says why the stream stopped. + } + return yield* execution; + }); + return { + ok: result.ok, + failure: result.ok ? "" : result.error.message, + output: chunks.join(""), + events: stream.snapshot(), + }; + }); +} + +/** Every appended `agent_prompt`, in journal order, with its coroutine. */ +function prompts(events: readonly DurableEvent[]): Array<{ name: string; coroutineId: string }> { + return events + .filter((event) => event.type === "yield" && event.description.type === "agent_prompt") + .map((event) => ({ + name: event.type === "yield" ? event.description.name : "", + coroutineId: event.coroutineId, + })); +} + +const TWO_SESSIONS = [ + "", + '', + '', + "", +].join("\n"); + +describe("Tier PA10a — two ordinary Sessions at the same time", () => { + beforeAll(() => useTempFileCompiler()); + + it("PA10a: both conversations are live, and releasing the second first renders in source order", function* () { + const held = conversations({ gated: true }); + const stream = new InMemoryStream(); + // The journal says when a record lands, so the second release waits on the + // first append rather than on a clock. + const recordedOne = signal(); + stream.onAppend = (event) => { + if (event.type === "yield" && event.description.type === "agent_prompt") { + recordedOne.publish(); + } + }; + const result = yield* talking(TWO_SESSIONS, held, { + stream, + *drive() { + // Both ordinary `` paths reach the provider before + // either is let go, which a sequential engine could never produce. + yield* held.reached("stub:planner"); + yield* held.reached("stub:reviewer"); + expect([...held.arrived].sort()).toEqual(["stub:planner", "stub:reviewer"]); + // The second spawn goes first, so its record appends first. + held.release("stub:reviewer"); + yield* awaiting("the reviewer recording its turn", recordedOne.published); + held.release("stub:planner"); + }, + }); + + expect(result.ok).toBe(true); + // One declared component, one implementation, one provider installation + // serving both branches — not a domain per spawn. + expect(held.sessions()).toBe(1); + expect(held.activations()).toBe(1); + + const recorded = prompts(result.events); + expect(recorded).toHaveLength(2); + // Completion order in the journal: the second spawn's child coroutine + // appended first, and each record is its own authored invocation. + expect(recorded.map((entry) => entry.coroutineId)).toEqual(["root.1", "root.0"]); + expect(new Set(recorded.map((entry) => entry.name)).size).toBe(2); + // And the document still renders in the order the spawns were written. + expect(result.output.indexOf("[stub:planner]")).toBeGreaterThanOrEqual(0); + expect(result.output.indexOf("[stub:planner]")).toBeLessThan( + result.output.indexOf("[stub:reviewer]"), + ); + }); +}); + +describe("Tier PA10c — nesting and replay with ordinary Sessions", () => { + beforeAll(() => useTempFileCompiler()); + + it("PA10c: a nested resolves two capability-backed children concurrently", function* () { + const held = conversations(); + const result = yield* talking( + [ + "", + "", + "", + '', + '', + "", + "", + '', + "", + ].join("\n"), + held, + ); + + expect(result.ok).toBe(true); + expect(held.sessions()).toBe(1); + const recorded = prompts(result.events); + expect(recorded).toHaveLength(3); + // Hierarchical child identity, source-ordered: a branch inside a branch + // owns its own frames as much as a top-level one does. + expect(new Set(recorded.map((entry) => entry.coroutineId))).toEqual( + new Set(["root.0.0", "root.0.1", "root.1"]), + ); + expect(new Set(recorded.map((entry) => entry.name)).size).toBe(3); + }); + + it("PA10c: a full replay calls no provider, and a partial one reaches only the unrecorded child", function* () { + const golden = conversations({ gated: true }); + const stream = new InMemoryStream(); + // The first child is released and allowed to close before the second does + // anything, so the truncation below has exactly one complete child and one + // that has not started its work. + const closedFirst = signal(); + stream.onAppend = (event) => { + if (event.type === "close" && event.coroutineId === "root.0") { + closedFirst.publish(); + } + }; + const first = yield* talking(TWO_SESSIONS, golden, { + stream, + *drive() { + yield* golden.reached("stub:planner"); + yield* golden.reached("stub:reviewer"); + golden.release("stub:planner"); + yield* awaiting("the first child closing", closedFirst.published); + golden.release("stub:reviewer"); + }, + }); + expect(first.ok).toBe(true); + expect(golden.arrived).toHaveLength(2); + + // Nothing spawned runs again: both children closed, so replay reads their + // recorded results. + const replayed = conversations(); + const whole = yield* talking(TWO_SESSIONS, replayed, { + stream: new InMemoryStream(first.events), + }); + expect(whole.ok).toBe(true); + expect(replayed.arrived).toEqual([]); + expect(whole.output).toBe(first.output); + + // Cut after the first child closed. The completed child is restored and + // only the other one reaches a provider, under the same child identity. + const closedAt = first.events.findIndex( + (event) => event.type === "close" && event.coroutineId === "root.0", + ); + expect(closedAt).toBeGreaterThan(0); + const cut = first.events.slice(0, closedAt + 1); + // Exactly one complete child, and nothing recorded for the other. + expect(cut.some((event) => event.type === "close" && event.coroutineId === "root.1")).toBe( + false, + ); + expect(prompts(cut).map((entry) => entry.coroutineId)).toEqual(["root.0"]); + + const resumed = conversations(); + const partial = yield* talking(TWO_SESSIONS, resumed, { stream: new InMemoryStream(cut) }); + expect(partial.ok).toBe(true); + // Only the child with no close reached a provider, and it is the other one. + expect(resumed.arrived).toEqual(["stub:reviewer"]); + expect(partial.output).toBe(first.output); + expect(prompts(partial.events).map((entry) => entry.coroutineId)).toEqual(["root.0", "root.1"]); + }); +}); diff --git a/packages/core/tests/answer-identity.test.ts b/packages/core/tests/answer-identity.test.ts index ae71982e3..f3e52cbf6 100644 --- a/packages/core/tests/answer-identity.test.ts +++ b/packages/core/tests/answer-identity.test.ts @@ -29,7 +29,8 @@ import { describe, it } from "@executablemd/test-support/bdd"; import { expect } from "@executablemd/test-support/expect"; -import type { Operation } from "effection"; +import { all, race, scoped, sleep, useScope, withResolvers } from "effection"; +import type { Operation, Scope } from "effection"; import { AnswerIdentityError, @@ -50,6 +51,83 @@ const IDENTITY: AnswerIdentity = { origin: ORIGIN, key: "Open", revision: "1" }; const OPEN = { key: "Open", revision: "1" } as const; const OTHER = { key: "Other", revision: "1" } as const; +/** + * Where two branches wait for each other. + * + * A window belongs to the engine scope that opened it, so the rows about two + * branches at once are written as two operations that each own their own scope + * and read it from inside. Nothing hands a `Scope` out of the operation that + * owns it, and a window never outlives the body that opened it. + * + * What is left is the coordination: both branches have to be *open together*, + * which is the whole point, and neither may run ahead. Each step is a counter + * and one signal — the party that completes it releases everybody waiting on + * it, and a step that never completes is reported as a deadlock rather than + * waited on forever. + */ +function rendezvous(parties: number): (step: string) => Operation { + const steps = new Map(); + return function meet(step: string): Operation { + let slot = steps.get(step); + if (slot === undefined) { + slot = { arrived: 0, reached: signal() }; + steps.set(step, slot); + } + const waiting = slot; + return (function* () { + waiting.arrived += 1; + if (waiting.arrived >= parties) { + waiting.reached.publish(); + } + yield* awaiting(`both branches reaching "${step}"`, waiting.reached.published); + })(); + }; +} + +/** + * How long a step a correct engine completes immediately may go uncompleted + * before the wait is called a deadlock. + * + * Never reached by a passing run: every step below is completed by the other + * branch. It bounds only the failure mode, so a defect that stops one branch + * says which step it stopped at instead of hanging the suite. + */ +const DEADLOCK_MS = 10_000; + +interface Signal { + publish(): void; + readonly published: Operation; +} + +function signal(): Signal { + const resolvers = withResolvers(); + let settled = false; + return { + publish() { + if (!settled) { + settled = true; + resolvers.resolve(true); + } + }, + get published() { + return resolvers.operation; + }, + }; +} + +function* awaiting(what: string, waited: Operation): Operation { + const reached = yield* race([ + waited, + (function* (): Operation { + yield* sleep(DEADLOCK_MS); + return false; + })(), + ]); + if (!reached) { + throw new Error(`${what} never happened`); + } +} + /** One owner, activated the way canonical execution activates it. */ function owner(): CanonicalImports { const imports = new CanonicalImports(); @@ -68,8 +146,9 @@ function resolving( imports: CanonicalImports, name: string, work: (resolution: ResolutionWindow) => T, + scope: Scope, ): T { - const resolution = imports.beginResolution(name); + const resolution = imports.beginResolution(name, scope); try { return work(resolution); } finally { @@ -88,8 +167,9 @@ function asking( installation: ProviderInstallation, name: string, work: (request: ComponentAnswerRequest) => T, + scope: Scope, ): T { - const asked = installation.open(name); + const asked = installation.open(scope, name); try { return work(asked.request); } finally { @@ -127,27 +207,39 @@ function refusalOf(attempt: () => unknown): unknown { describe("Tier CIV — an identity belongs to one answer of one import", () => { it("CIV23: an identity is stated on the exact answer and read back", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, supplied } = resolving(imports, "Open", (resolution) => ({ - resolution, - supplied: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), - })); + const { resolution, supplied } = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + supplied: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), + }), + here, + ); expect(imports.identify(resolution, supplied)?.identity).toEqual(IDENTITY); expect(identityRecord(IDENTITY)).toBe("test://provider#Open@1"); }); it("CIV24: identification answers with the claim-time copy, not the answer", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const supplied = answer(); - const resolution = resolving(imports, "Open", (resolution) => { - asking(provider, "Open", (request) => request.claim(supplied, OPEN)); - return resolution; - }); + const resolution = resolving( + imports, + "Open", + (resolution) => { + asking(provider, "Open", (request) => request.claim(supplied, OPEN), here); + return resolution; + }, + here, + ); // One call answers both halves. The definition is core's own copy, taken // when the claim was recorded — so a caller that keeps what identification @@ -163,6 +255,7 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV24: an alternating answer cannot launder a copy through a second read", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const honest = answer(); @@ -182,10 +275,15 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }, }) as ImportedDefinition; - const resolution = resolving(imports, "Open", (resolution) => { - asking(provider, "Open", (request) => request.claim(alternating, OPEN)); - return resolution; - }); + const resolution = resolving( + imports, + "Open", + (resolution) => { + asking(provider, "Open", (request) => request.claim(alternating, OPEN), here); + return resolution; + }, + here, + ); const identified = imports.identify(resolution, alternating); // The claim itself was recorded from the first reading, and identification @@ -200,53 +298,81 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: restating exactly the same claim is idempotent", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const supplied = answer(); - const resolution = resolving(imports, "Open", (resolution) => { - asking(provider, "Open", (request) => { - request.claim(supplied, OPEN); - // A provider installed twice states the same thing twice. That is not - // two providers disagreeing, and it is not a conflict. - expect(refusalOf(() => request.claim(supplied, OPEN))).toBe(undefined); - }); - return resolution; - }); + const resolution = resolving( + imports, + "Open", + (resolution) => { + asking( + provider, + "Open", + (request) => { + request.claim(supplied, OPEN); + // A provider installed twice states the same thing twice. That is not + // two providers disagreeing, and it is not a conflict. + expect(refusalOf(() => request.claim(supplied, OPEN))).toBe(undefined); + }, + here, + ); + return resolution; + }, + here, + ); expect(imports.identify(resolution, supplied)?.identity).toEqual(IDENTITY); }); it("CIV23: a competing claim refuses and never overwrites the first", function* () { + const here = yield* useScope(); const imports = owner(); const first = imports.provider(ORIGIN); const second = imports.provider("test://other"); const held = answer(); - const resolution = resolving(imports, "Open", (resolution) => { - asking(first, "Open", (request) => request.claim(held, OPEN)); - // Another installation, asked in the same live resolution, cannot rename - // what the first stated. An overwrite would let a second provider take - // the first's implementation. - asking(second, "Open", (request) => { - expect(refusalOf(() => request.claim(held, OPEN))).toBeInstanceOf(AnswerIdentityError); - }); - // And the first installation's *next* invocation cannot restate it - // differently either. - asking(first, "Open", (request) => { - expect( - refusalOf(() => request.claim(held, { key: "Other", revision: "1" })), - ).toBeInstanceOf(AnswerIdentityError); - expect(refusalOf(() => request.claim(held, { key: "Open", revision: "2" }))).toBeInstanceOf( - AnswerIdentityError, + const resolution = resolving( + imports, + "Open", + (resolution) => { + asking(first, "Open", (request) => request.claim(held, OPEN), here); + // Another installation, asked in the same live resolution, cannot rename + // what the first stated. An overwrite would let a second provider take + // the first's implementation. + asking( + second, + "Open", + (request) => { + expect(refusalOf(() => request.claim(held, OPEN))).toBeInstanceOf(AnswerIdentityError); + }, + here, ); - }); - return resolution; - }); + // And the first installation's *next* invocation cannot restate it + // differently either. + asking( + first, + "Open", + (request) => { + expect( + refusalOf(() => request.claim(held, { key: "Other", revision: "1" })), + ).toBeInstanceOf(AnswerIdentityError); + expect( + refusalOf(() => request.claim(held, { key: "Open", revision: "2" })), + ).toBeInstanceOf(AnswerIdentityError); + }, + here, + ); + return resolution; + }, + here, + ); expect(imports.identify(resolution, held)?.identity).toEqual(IDENTITY); }); it("CIV25: a request whose handler has returned states nothing", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const late = answer(); @@ -257,23 +383,34 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { // the execution is still very much alive. What has ended is this // invocation, and an invocation that has returned is not supplying an // answer. - const resolution = resolving(imports, "Open", (resolution) => { - asking(provider, "Open", (request) => { - stale = request; - }); - expect(refusalOf(() => stale?.claim(late, OPEN))).toBeInstanceOf(AnswerIdentityError); - // The positive control in the same still-open window: a fresh invocation - // of the same installation claims, so the refusal above is about the - // handler lease rather than about the window or the provider. - asking(provider, "Open", (request) => request.claim(answer(), OPEN)); - return resolution; - }); + const resolution = resolving( + imports, + "Open", + (resolution) => { + asking( + provider, + "Open", + (request) => { + stale = request; + }, + here, + ); + expect(refusalOf(() => stale?.claim(late, OPEN))).toBeInstanceOf(AnswerIdentityError); + // The positive control in the same still-open window: a fresh invocation + // of the same installation claims, so the refusal above is about the + // handler lease rather than about the window or the provider. + asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); + return resolution; + }, + here, + ); expect(imports.identify(resolution, late)).toBe(undefined); expect(imports.identifying).toBe(true); }); it("CIV25: a stale request cannot answer the next resolution of its own name", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const fresh = answer(); @@ -281,27 +418,47 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { let stale: ComponentAnswerRequest | undefined; // Resolution N of `Open`, whose handler keeps its request. - resolving(imports, "Open", () => { - asking(provider, "Open", (request) => { - requests.push(request); - stale = request; - }); - }); + resolving( + imports, + "Open", + () => { + asking( + provider, + "Open", + (request) => { + requests.push(request); + stale = request; + }, + here, + ); + }, + here, + ); // Resolution N+1 of the same name. The stale request names the right // component and belongs to an import that is over. - const { resolution, claimed } = resolving(imports, "Open", (resolution) => { - expect(refusalOf(() => stale?.claim(fresh, OPEN))).toBeInstanceOf(AnswerIdentityError); - // The same installation is asked again and answers this resolution: the - // installation is reusable, the request is not. - return { - resolution, - claimed: asking(provider, "Open", (request) => { - requests.push(request); - return request.claim(answer(), OPEN); - }), - }; - }); + const { resolution, claimed } = resolving( + imports, + "Open", + (resolution) => { + expect(refusalOf(() => stale?.claim(fresh, OPEN))).toBeInstanceOf(AnswerIdentityError); + // The same installation is asked again and answers this resolution: the + // installation is reusable, the request is not. + return { + resolution, + claimed: asking( + provider, + "Open", + (request) => { + requests.push(request); + return request.claim(answer(), OPEN); + }, + here, + ), + }; + }, + here, + ); expect(requests).toHaveLength(2); expect(requests[0]).not.toBe(requests[1]); @@ -310,33 +467,57 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: a stale request cannot retag while another name is being decided", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const substitute = answer("Other"); let stale: ComponentAnswerRequest | undefined; - resolving(imports, "Open", () => { - asking(provider, "Open", (request) => { - stale = request; - }); - }); + resolving( + imports, + "Open", + () => { + asking( + provider, + "Open", + (request) => { + stale = request; + }, + here, + ); + }, + here, + ); // `claim` takes no name, so the stale request cannot even ask about the // name being decided: it is fixed to `Open`, which this resolution is not. - const { resolution, claimed } = resolving(imports, "Other", (resolution) => { - expect(stale?.name).toBe("Open"); - expect(refusalOf(() => stale?.claim(substitute, OTHER))).toBeInstanceOf(AnswerIdentityError); - return { - resolution, - claimed: asking(provider, "Other", (request) => request.claim(answer("Other"), OTHER)), - }; - }); + const { resolution, claimed } = resolving( + imports, + "Other", + (resolution) => { + expect(stale?.name).toBe("Open"); + expect(refusalOf(() => stale?.claim(substitute, OTHER))).toBeInstanceOf( + AnswerIdentityError, + ); + return { + resolution, + claimed: asking( + provider, + "Other", + (request) => request.claim(answer("Other"), OTHER), + here, + ), + }; + }, + here, + ); expect(imports.identify(resolution, substitute)).toBe(undefined); expect(imports.identify(resolution, claimed)?.identity.key).toBe("Other"); }); it("CIV25: one installation answers two names through two distinct requests", function* () { + const here = yield* useScope(); const imports = owner(); // One installation owns one origin and may answer more than one admitted // name. Spending the installation on its first answer would break exactly @@ -344,20 +525,40 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { const provider = imports.provider(ORIGIN); const seen: ComponentAnswerRequest[] = []; - const open = resolving(imports, "Open", (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => { - seen.push(request); - return request.claim(answer(), OPEN); + const open = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + claimed: asking( + provider, + "Open", + (request) => { + seen.push(request); + return request.claim(answer(), OPEN); + }, + here, + ), }), - })); - const other = resolving(imports, "Other", (resolution) => ({ - resolution, - claimed: asking(provider, "Other", (request) => { - seen.push(request); - return request.claim(answer("Other"), OTHER); + here, + ); + const other = resolving( + imports, + "Other", + (resolution) => ({ + resolution, + claimed: asking( + provider, + "Other", + (request) => { + seen.push(request); + return request.claim(answer("Other"), OTHER); + }, + here, + ), }), - })); + here, + ); // Two invocations, two requests, each fixed to what it was asked. expect(seen).toHaveLength(2); @@ -368,24 +569,45 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: identification takes the window it was asked about", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const requests: ComponentAnswerRequest[] = []; - const first = resolving(imports, "Open", (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => { - requests.push(request); - return request.claim(answer(), OPEN); + const first = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + claimed: asking( + provider, + "Open", + (request) => { + requests.push(request); + return request.claim(answer(), OPEN); + }, + here, + ), }), - })); - const second = resolving(imports, "Open", (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => { - requests.push(request); - return request.claim(answer(), OPEN); + here, + ); + const second = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + claimed: asking( + provider, + "Open", + (request) => { + requests.push(request); + return request.claim(answer(), OPEN); + }, + here, + ), }), - })); + here, + ); // Each answer belongs to the import it answered, and to no other. Nothing // here reads whichever window is current: the caller presents the one it @@ -399,42 +621,54 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: a request shows the asked position by value", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); // The engine's own object, which it reads again after any handler has seen // it. A provider is shown a copy, like everything else it is shown. const scanned = { path: "doc.md", offset: 12, line: 3, column: 5 }; - resolving(imports, "Open", () => { - const asked = provider.open("Open", scanned); - try { - const shown = asked.request.position; - expect(shown).toEqual(scanned); - expect(shown).not.toBe(scanned); - // Editing what the handler was given reaches nothing, and the request - // itself cannot be re-pointed at another element. - expect(() => { - (shown as { line: number }).line = 99; - }).toThrow(); - expect(() => { - (asked.request as { name: string }).name = "Other"; - }).toThrow(); - } finally { - asked.close(); - } - // And the engine's own object is untouched by having been shown. - expect(scanned).toEqual({ path: "doc.md", offset: 12, line: 3, column: 5 }); - }); + resolving( + imports, + "Open", + () => { + const asked = provider.open(here, "Open", scanned); + try { + const shown = asked.request.position; + expect(shown).toEqual(scanned); + expect(shown).not.toBe(scanned); + // Editing what the handler was given reaches nothing, and the request + // itself cannot be re-pointed at another element. + expect(() => { + (shown as { line: number }).line = 99; + }).toThrow(); + expect(() => { + (asked.request as { name: string }).name = "Other"; + }).toThrow(); + } finally { + asked.close(); + } + // And the engine's own object is untouched by having been shown. + expect(scanned).toEqual({ path: "doc.md", offset: 12, line: 3, column: 5 }); + }, + here, + ); }); it("CIV23: a different object carries no claim, however alike", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, claimed } = resolving(imports, "Open", (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), - })); + const { resolution, claimed } = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), + }), + here, + ); expect(imports.identify(resolution, claimed)?.identity).toEqual(IDENTITY); // The outer-replacement case: a handler further out returns its own object, @@ -445,13 +679,19 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: editing the claimed answer invalidates the claim", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, claimed } = resolving(imports, "Open", (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), - })); + const { resolution, claimed } = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), + }), + here, + ); expect(imports.identify(resolution, claimed)?.identity).toEqual(IDENTITY); // The same object, edited after the claim by a handler further out. What @@ -462,21 +702,29 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: an installation retained past its execution opens nothing", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, before } = resolving(imports, "Open", (resolution) => ({ - resolution, - before: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), - })); + const { resolution, before } = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + before: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), + }), + here, + ); expect(imports.identify(resolution, before)?.identity).toEqual(IDENTITY); imports.revoke(); // The installation is the object a provider kept. The window it would need // cannot be opened, and a request minted from it states nothing. - expect(refusalOf(() => imports.beginResolution("Open"))).toBeInstanceOf(AnswerIdentityError); + expect(refusalOf(() => imports.beginResolution("Open", here))).toBeInstanceOf( + AnswerIdentityError, + ); expect( - refusalOf(() => asking(provider, "Open", (request) => request.claim(answer(), OPEN))), + refusalOf(() => asking(provider, "Open", (request) => request.claim(answer(), OPEN), here)), ).toBeInstanceOf(AnswerIdentityError); // And what it stated while the execution was live identifies nothing now: // an admission may not be reconciled against a run that is over. @@ -485,36 +733,53 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: an owner starts inactive, so a claim before activation refuses", function* () { + const here = yield* useScope(); const imports = new CanonicalImports(); // Canonical execution registers teardown, then activates, then installs // providers. A claim that landed before activation would be a claim with no // teardown behind it. expect(imports.identifying).toBe(false); - expect(refusalOf(() => imports.beginResolution("Open"))).toBeInstanceOf(AnswerIdentityError); + expect(refusalOf(() => imports.beginResolution("Open", here))).toBeInstanceOf( + AnswerIdentityError, + ); expect( refusalOf(() => - asking(imports.provider(ORIGIN), "Open", (request) => request.claim(answer(), OPEN)), + asking(imports.provider(ORIGIN), "Open", (request) => request.claim(answer(), OPEN), here), ), ).toBeInstanceOf(AnswerIdentityError); }); it("CIV25: overlapping executions are isolated", function* () { + const here = yield* useScope(); const first = owner(); const second = owner(); const shared = answer(); - const one = resolving(first, "Open", (resolution) => { - asking(first.provider(ORIGIN), "Open", (request) => request.claim(shared, OPEN)); - return resolution; - }); + const one = resolving( + first, + "Open", + (resolution) => { + asking(first.provider(ORIGIN), "Open", (request) => request.claim(shared, OPEN), here); + return resolution; + }, + here, + ); // Live at the same time, and each answers only for what it recorded. - const two = resolving(second, "Open", (resolution) => { - expect(second.identify(resolution, shared)).toBe(undefined); - asking(second.provider(ORIGIN), "Open", (request) => - request.claim(shared, { key: "Open", revision: "2" }), - ); - return resolution; - }); + const two = resolving( + second, + "Open", + (resolution) => { + expect(second.identify(resolution, shared)).toBe(undefined); + asking( + second.provider(ORIGIN), + "Open", + (request) => request.claim(shared, { key: "Open", revision: "2" }), + here, + ); + return resolution; + }, + here, + ); expect(first.identify(one, shared)?.identity).toEqual(IDENTITY); expect(second.identify(two, shared)?.identity).toEqual({ @@ -530,20 +795,30 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: a provider cannot state an origin canonical execution did not give it", function* () { + const here = yield* useScope(); const imports = owner(); // The installation carries the origin; the provider states only key and // revision. There is no member on the claim call to put another origin in. - const { resolution, claimed } = resolving(imports, "Open", (resolution) => ({ - resolution, - claimed: asking(imports.provider("test://assigned"), "Open", (request) => - request.claim(answer(), OPEN), - ), - })); + const { resolution, claimed } = resolving( + imports, + "Open", + (resolution) => ({ + resolution, + claimed: asking( + imports.provider("test://assigned"), + "Open", + (request) => request.claim(answer(), OPEN), + here, + ), + }), + here, + ); expect(imports.identify(resolution, claimed)?.identity.origin).toBe("test://assigned"); }); it("CIV23: a partial identity is refused rather than recorded", function* () { + const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const attempts = [ @@ -553,14 +828,24 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { for (const attempt of attempts) { const supplied = answer(); - const resolution = resolving(imports, "Open", (resolution) => { - asking(provider, "Open", (request) => { - expect(refusalOf(() => request.claim(supplied, attempt))).toBeInstanceOf( - AnswerIdentityError, + const resolution = resolving( + imports, + "Open", + (resolution) => { + asking( + provider, + "Open", + (request) => { + expect(refusalOf(() => request.claim(supplied, attempt))).toBeInstanceOf( + AnswerIdentityError, + ); + }, + here, ); - }); - return resolution; - }); + return resolution; + }, + here, + ); // Refused rather than partially recorded: a half identity would compare // equal to a different half identity. expect(imports.identify(resolution, supplied)).toBe(undefined); @@ -568,15 +853,245 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: an answer nobody claimed identifies nothing", function* () { + const here = yield* useScope(); const imports = owner(); // The ordinary case, and the reason this is not a permission: an unidentified // answer is a perfectly good answer. What it cannot be is the thing a // fragment runs, because a continuation would have nothing to compare. - resolving(imports, "Open", (resolution) => { - expect(imports.identify(resolution, answer())).toBe(undefined); - expect(imports.identify(resolution, undefined)).toBe(undefined); - expect(imports.identify(resolution, null)).toBe(undefined); - expect(imports.identify(resolution, "Open")).toBe(undefined); + resolving( + imports, + "Open", + (resolution) => { + expect(imports.identify(resolution, answer())).toBe(undefined); + expect(imports.identify(resolution, undefined)).toBe(undefined); + expect(imports.identify(resolution, null)).toBe(undefined); + expect(imports.identify(resolution, "Open")).toBe(undefined); + }, + here, + ); + }); +}); + +/** + * Tier PA10b — two branches resolving at the same time. + * + * `` lets two `` children have an import open together, so a + * resolution is no longer the only one in flight. What makes an answer this + * import's is the exact window it was asked in, and windows now belong to the + * engine scope that opened them — so these rows are written with two real + * scopes standing for two branches, and never with one branch's bookkeeping + * standing in for the other's. + */ +describe("Tier PA10b — concurrent resolution windows", () => { + it("PA10b: one installation answers two windows open at the same time", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const meet = rendezvous(2); + const answers = new Map(); + + /** + * One branch, resolving in a scope of its own. + * + * Everything the branch owns is opened and settled inside this operation: + * it reads its own scope here, keeps its window and its request for as long + * as the operation lasts, and hands nothing but its answer back. The two + * run together under `all`, held at a rendezvous so neither can finish + * before the other has opened — which is what makes two windows genuinely + * open at once rather than one after the other. + */ + const resolve = (name: string) => + scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + // Both windows are open before either branch claims, which is the + // shape two `` children produce and the only arrangement in + // which a claim could land in the wrong one. + yield* meet("both open"); + answers.set( + name, + asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), + ); + yield* meet("claimed"); + // Both branches have answered and both windows are still open, so + // the cross-checks are made while the other one really exists. + const mine = answers.get(name)!; + const other = answers.get(name === "left" ? "right" : "left")!; + expect(imports.identify(window, mine)?.identity).toEqual(IDENTITY); + expect(imports.identify(window, other)).toBe(undefined); + yield* meet("checked"); + } finally { + window.close(); + } + }); + + yield* all([resolve("left"), resolve("right")]); + // Two distinct answers, neither overwritten by the other's claim. + expect(answers.size).toBe(2); + expect(answers.get("left")).not.toBe(answers.get("right")); + }); + + it("PA10b: a request answers its own branch and refuses the sibling's", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const meet = rendezvous(2); + + const mine = scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + const kept = provider.open(here, "Open"); + // Held open while the sibling's window is the last one opened anywhere. + // Being the most recent window in the execution is not being the window + // this handler was asked in. + yield* meet("both open"); + expect(imports.identify(window, kept.request.claim(answer(), OPEN))?.identity).toEqual( + IDENTITY, + ); + kept.close(); + // And once closed it answers nothing at all. + expect(refusalOf(() => kept.request.claim(answer(), OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + yield* meet("done"); + } finally { + window.close(); + } + }); + + const sibling = scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + yield* meet("both open"); + yield* meet("done"); + } finally { + window.close(); + } + }); + + yield* all([mine, sibling]); + }); + + it("PA10b: a second different answer in one window refuses, whatever the sibling did", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const meet = rendezvous(2); + const refused: unknown[] = []; + + const first = scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); + // The sibling answers in between, which is what an installation that + // remembered only its most recent window would treat as un-spending + // this one. + yield* meet("answered once"); + yield* meet("sibling answered"); + refused.push( + refusalOf(() => + asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), + ), + ); + } finally { + window.close(); + } + }); + + const other = scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + yield* meet("answered once"); + asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); + yield* meet("sibling answered"); + } finally { + window.close(); + } + }); + + yield* all([first, other]); + expect(refused).toHaveLength(1); + expect(refused[0]).toBeInstanceOf(AnswerIdentityError); + }); + + it("PA10b: one branch ending leaves the other live, and teardown leaves neither", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const meet = rendezvous(2); + const identified: unknown[] = []; + + // This branch simply ends, which is what a spawn child answering, failing + // or being cancelled looks like from the owner's side: its scope goes, and + // with it every window it had open. + const ending = scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + yield* meet("both open"); + } finally { + window.close(); + } + }); + + const continuing = scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + yield* meet("both open"); + yield* meet("the other ended"); + // Still deciding, and still claimable: the branch that ended neither + // cleared this window nor authorized anything in it. + const still = asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); + identified.push(imports.identify(window, still)?.identity); + } finally { + window.close(); + } + }); + + yield* all([ + (function* (): Operation { + yield* ending; + yield* meet("the other ended"); + })(), + continuing, + ]); + expect(identified).toEqual([IDENTITY]); + + // And once the owner is torn down nothing may be resolved at all, in any + // scope — asked inside an operation that owns the scope it asks with. + yield* scoped(function* () { + const here = yield* useScope(); + imports.revoke(); + expect(refusalOf(() => imports.beginResolution("Open", here))).toBeInstanceOf( + AnswerIdentityError, + ); + }); + }); + + it("PA10b: a nested resolution owns the top of its own branch until it closes", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + + yield* scoped(function* () { + const here = yield* useScope(); + const outer = imports.beginResolution("Open", here); + const held = provider.open(here, "Open"); + // The nested resolution is for the *same* name, which is the case a check + // written against the name rather than the exact window would admit. + const inner = imports.beginResolution("Open", here); + // The inner resolution hides its parent: a request minted for the outer + // one states nothing while something nested is deciding. + expect(refusalOf(() => held.request.claim(answer(), OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + inner.close(); + // And the parent is claimable again once the nested one is over. + const supplied = held.request.claim(answer(), OPEN); + expect(imports.identify(outer, supplied)?.identity).toEqual(IDENTITY); + held.close(); + outer.close(); }); }); }); diff --git a/packages/core/tests/invocation-identity.test.ts b/packages/core/tests/invocation-identity.test.ts index afecba752..beef07b41 100644 --- a/packages/core/tests/invocation-identity.test.ts +++ b/packages/core/tests/invocation-identity.test.ts @@ -158,7 +158,6 @@ function* nothing(): Operation {} * issuances — or one the engine has already ended — are stated here, at the * seam, with the issuances the engine would have minted. */ -// deno-lint-ignore require-yield function* seam(): Operation<{ claim: IdentityClaimant; domain: IdentityDomain }> { let claim: IdentityClaimant | undefined; const installed = installIdentities([ @@ -182,13 +181,21 @@ function* seam(): Operation<{ claim: IdentityClaimant; domain: IdentityDomain }> if (claim === undefined || registration === undefined) { throw new Error("the seam produced no claimant"); } - const frame = installed.identities.beginImport("Both"); - installed.identities.select("Both", { - kind: "function", - name: "Both", - props: NO_PROPS, - fn: registration.fn, - }); + // The seam's own scope, because this seam is not about branching: a frame + // belongs to the engine scope that opened it, and this one already runs in a + // scope its caller owns. + const branch = yield* useScope(); + const frame = installed.identities.beginImport("Both", branch); + installed.identities.select( + "Both", + { + kind: "function", + name: "Both", + props: NO_PROPS, + fn: registration.fn, + }, + branch, + ); const domain = frame.settle(); if (domain === undefined) { throw new Error("canonical selection produced no domain"); @@ -1029,3 +1036,56 @@ describe("Tier CIV — the authored form on the invocation", () => { expect(refusals.at(-1)).toEqual("refused:paired"); }); }); + +/** + * Tier PA10b — one declared component, two branches at once. + * + * `` gives two `` children imports in flight together. What puts an + * invocation in this execution's identity domain is the canonical selection + * made inside the frame its own import opened — so these rows are the general + * statement of the thing an ordinary `` in each branch needs. + */ +describe("Tier PA10b — concurrent capability-backed identity", () => { + it("PA10b: two concurrent sites each claim their own identity, exactly once", function* () { + const seen = record(); + yield* run( + ["", "", "", ""].join("\n"), + [probe(seen)], + nothing, + ); + + // Both claimed, neither refused, and neither received the other's. + expect(seen.refusals).toEqual([]); + expect(seen.taken).toHaveLength(2); + expect(new Set(seen.taken).size).toBe(2); + // The engine's own identity for each invocation, which is what + // `getExpansion()` reports when nothing has interfered. + expect(seen.taken).toEqual(seen.context); + }); + + it("PA10b: a nested inside a spawn claims its own identities too", function* () { + const seen = record(); + yield* run( + [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + ].join("\n"), + [probe(seen)], + nothing, + ); + + // Three sites, three identities, no refusal: a branch nested inside a + // branch owns its own frames as much as a top-level one does. + expect(seen.refusals).toEqual([]); + expect(seen.taken).toHaveLength(3); + expect(new Set(seen.taken).size).toBe(3); + expect(seen.taken).toEqual(seen.context); + }); +}); diff --git a/packages/core/tests/syntax-catalog.test.ts b/packages/core/tests/syntax-catalog.test.ts index ac42c99a2..007ae2156 100644 --- a/packages/core/tests/syntax-catalog.test.ts +++ b/packages/core/tests/syntax-catalog.test.ts @@ -377,6 +377,7 @@ describe("Tier SY: structural vocabulary", () => { // The reserved vocabulary in full, so a construct returning to the table // has to be written down here before this row can pass again. expect([...names(structural(catalog))].sort()).toEqual([ + "All", "Answer", "Answers", "Break", @@ -390,6 +391,7 @@ describe("Tier SY: structural vocabulary", () => { "Output", "PrintErrors", "Return", + "Spawn", "Switch", ]); for (const name of ["Terminal.Grid", "Terminal"]) { diff --git a/specs/executable-mdx-spec.md b/specs/executable-mdx-spec.md index df5e786b0..3539ccc16 100644 --- a/specs/executable-mdx-spec.md +++ b/specs/executable-mdx-spec.md @@ -5496,6 +5496,20 @@ registration canonical resolution selected — recognized there by the identity the implementation this execution built, carried to the issuance through the engine's own import frame (§5.3), and settled to nothing when resolution did not happen, happened twice, or answered for a name the engine did not ask. + +An import frame belongs to the Effection scope that opened it, and each scope +keeps its own innermost-last stack of them. Nesting inside one scope is +unchanged: an inner import owns the top until it closes, after which the outer +one may be selected into again. What the ownership adds is branching. Two +`` children under one `` may have imports open at the same time, and +each one's canonical selection is recorded into its own branch's frame — so an +ordinary `` written in each child receives its own authentic identity, +neither child can be handed the other's, and closing or cancelling one branch +neither clears nor authorizes the other. Two selections in one frame still +settle to nothing. The engine holds one domain per declared component per +execution however many branches invoke it, and the same ownership governs the +windows a provider's claim is admitted in: one installation may answer in two +branches at once, while a second, different answer in either refuses. Forwarding the genuine issuance is ordinary delegation and stays supported; everything else refuses. None of it reads replaceable state, so middleware may short-circuit an import, redirect a name, replace a definition, shadow a @@ -6743,6 +6757,84 @@ a rejected element also ending the loop. Printed errors from `` and `` carry source locations on the same terms as ``. +#### `` and ``: running independent work at the same time + +`` runs its direct `` children at the same time and waits for every +one of them. Both names are the engine's own syntax: neither resolves a +component, so a repository file, a registration or a Plugin cannot supply +either. + +```markdown + + + +Draft the implementation plan. + + + + +Review the current change. + + + +``` + +Both children can be live together, and `` renders their markdown in the +order the spawns were written even when the second one finishes first. + +**Form.** Both constructs are written paired and accept no props. `` +requires at least two direct `` children; whitespace between them is +insignificant, and any other direct content — text, a component, a code block — +is refused. A `` written anywhere but directly inside an `` is +refused too. Every one of these is read from source, so a malformed construct +refuses before any child starts: a tripwire written inside either child never +runs. + +**Bindings and resources.** Every child starts from the bindings that reached +the ``, in an environment of its own, with its own eval scope. A binding it +makes, a binding it rebinds and a resource it retains stay available to that +child's own later work, and reach neither a sibling nor the work after +``. Children do not communicate through bindings, and `` takes no +`as` and produces no value. A retained resource is released when its child ends. + +**Output.** Each child expands into a private buffer. After every child +succeeds, `` emits their renderings in authored order; before that it emits +none of them. Scheduling may decide when a child's durable records append, and +never what the document renders. + +**Durable identity and replay.** In source order, each `` receives one +child coroutine of the coroutine that reached the ``, allocated before any +child starts; nesting produces the existing hierarchical identity (§5.6, and the +protocol's §7). Each child also gets a fresh block counter and an expansion path +extended by its authored ordinal, so two children may derive the same local block +id without colliding — the child coroutine namespaces it — and the work after +`` continues on the parent counter it would have had anyway. Each +successful child closes with its rendered string. A complete replay runs no +spawned work and rebuilds the output from those closes; a partial replay +restores the children that closed and resumes only the unrecorded ones, under +the same identities. Inserting, removing or reordering spawns is a definition +change and follows the ordinary divergence contract. + +**Failure and cancellation.** The join is fail-fast. The first child failure +fails the ``, cancels every unfinished sibling and waits for all of them to +finish tearing down. No child output is emitted, durable records acknowledged +before the failure stay durable, and interrupted work is never recorded as +complete. Cancelling the document cancels and joins every child; no task, +subscription, retained resource or output buffer survives its spawn. + +**Control flow.** `` is a boundary. A `` inside one cannot select +a value owned outside the ``, and a `` inside one cannot exit a +`` written outside it; both are refused from source, before anything runs. +A component invoked inside the child owns its own ``, and a `` +written wholly inside the child is ended by its own ``, exactly as +elsewhere. A `` below a `` neither satisfies nor violates the +enclosing body's own `returns` declaration: the body still owes the `` +it declared. + +Generated XMD receives the same syntax and the same rules. The whole-fragment +preflight walks every spawn — each from the bindings that reach the ``, and +merging nothing back — before the fragment performs its first effect. + ### 6.6 Eval binding interpolation Bare `{name}` references (no namespace prefix) resolve against From 40742e65426218b7f361d6291e3c4468242d159f Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Mon, 28 Sep 2026 17:57:37 -0400 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9A=A1=20Measure=20test=20weights=20at?= =?UTF-8?q?=20b14a2ba1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The artifact of run 36473005680, unchanged. `` and `` add one test file and change what several others run, and a weight is only true of the runner that measured it. --- test-weights.json | 2149 +++++++++++++++++++++++---------------------- 1 file changed, 1076 insertions(+), 1073 deletions(-) diff --git a/test-weights.json b/test-weights.json index cd8f17f35..6f8199aec 100644 --- a/test-weights.json +++ b/test-weights.json @@ -1,8 +1,8 @@ { "version": 1, "source": { - "commit": "a403cc57170514db95722ce7926aec5515f92453", - "runUrl": "https://github.com/taras/executable.md/actions/runs/36417683621", + "commit": "b14a2ba145364f38604cadba373f40a411242899", + "runUrl": "https://github.com/taras/executable.md/actions/runs/36473005680", "attempt": 1, "runner": "ubuntu-latest", "deno": "deno 2.9.5 (stable, release, x86_64-unknown-linux-gnu)", @@ -11,1094 +11,1097 @@ }, "runtimes": { "deno": { - "packages/acp/tests/acceptance.test.ts": 4890, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 7990, - "packages/acp/tests/acpx-materialization.test.ts": 8093, - "packages/acp/tests/acpx-transient-env.test.ts": 1812, - "packages/acp/tests/adapter-materialization.test.ts": 77274, - "packages/acp/tests/adapter-protocol.test.ts": 59906, - "packages/acp/tests/codex-surfaces.test.ts": 1784, - "packages/acp/tests/loaded-copy.test.ts": 4628, - "packages/acp/tests/native-launch.test.ts": 5345, - "packages/acp/tests/permission-bridge.test.ts": 4076, - "packages/acp/tests/provider.test.ts": 5260, - "packages/acp/tests/serial-queue.test.ts": 1533, - "packages/acp/tests/session-key.test.ts": 3980, - "packages/acp/tests/session-route.test.ts": 4132, - "packages/acp/tests/terminal-screen.test.ts": 1731, - "packages/cli/tests/agent-adapters.test.ts": 5722, - "packages/cli/tests/agent-cli.test.ts": 36964, - "packages/cli/tests/agent-config.test.ts": 3639, - "packages/cli/tests/agent-options-cli.test.ts": 15109, - "packages/cli/tests/agent-options.test.ts": 3659, - "packages/cli/tests/agent-session-coordinator.test.ts": 4348, - "packages/cli/tests/cli-help.test.ts": 20236, - "packages/cli/tests/command.test.ts": 10301, - "packages/cli/tests/compiled-upgrade.test.ts": 10637, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 9094, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 120013, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 8572, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 12296, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 10476, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 15699, - "packages/cli/tests/evaluate-component.test.ts": 11856, - "packages/cli/tests/evaluate-workflow.test.ts": 5562, - "packages/cli/tests/fetch-cli.test.ts": 3864, - "packages/cli/tests/file-stream.test.ts": 1811, - "packages/cli/tests/github-zero-effect.test.ts": 7260, - "packages/cli/tests/inline-cli.test.ts": 33591, - "packages/cli/tests/launch-timeout.test.ts": 11660, - "packages/cli/tests/packaged-document.test.ts": 4899, - "packages/cli/tests/plan-args.test.ts": 1597, - "packages/cli/tests/plan-cli.test.ts": 97616, - "packages/cli/tests/plan-command-document.test.ts": 9852, - "packages/cli/tests/plan-component.test.ts": 12024, - "packages/cli/tests/plan-host-acts.test.ts": 5483, - "packages/cli/tests/plan.test.ts": 16125, - "packages/cli/tests/plugin-cli.test.ts": 40561, - "packages/cli/tests/plugin-host.test.ts": 6162, - "packages/cli/tests/plugin-modules.test.ts": 1540, - "packages/cli/tests/plugin-selection.test.ts": 1528, - "packages/cli/tests/process-retention.test.ts": 5307, - "packages/cli/tests/props-cli.test.ts": 30410, - "packages/cli/tests/props-schema.test.ts": 4087, - "packages/cli/tests/props-sources.test.ts": 2293, - "packages/cli/tests/pull-request-read-fork.test.ts": 7148, - "packages/cli/tests/repl-boundaries.test.ts": 7654, - "packages/cli/tests/repl-composition.test.ts": 2084, - "packages/cli/tests/repl-execution.test.ts": 5446, - "packages/cli/tests/repl-journey.test.ts": 20562, - "packages/cli/tests/repl-model.test.ts": 5271, - "packages/cli/tests/repl-route.test.ts": 4830, - "packages/cli/tests/repl-terminal.test.ts": 2940, - "packages/cli/tests/run-composition-deno.test.ts": 7865, - "packages/cli/tests/run-composition-nested.test.ts": 20765, - "packages/cli/tests/run-composition.test.ts": 7086, - "packages/cli/tests/run-deadline.test.ts": 8852, - "packages/cli/tests/run-profile.test.ts": 4456, - "packages/cli/tests/run-timeouts.test.ts": 13293, - "packages/cli/tests/secret-detection-cli.test.ts": 19637, - "packages/cli/tests/service-document.test.ts": 5349, - "packages/cli/tests/service-host.test.ts": 5227, - "packages/cli/tests/session-launch-cli.test.ts": 10605, - "packages/cli/tests/stdin-cli.test.ts": 37206, - "packages/cli/tests/stdout-delivery.test.ts": 1542, - "packages/cli/tests/syntax-cli.test.ts": 36546, - "packages/cli/tests/targets-cli.test.ts": 28883, - "packages/cli/tests/test-root-profile.test.ts": 7230, - "packages/cli/tests/test-target.test.ts": 37366, - "packages/cli/tests/testing-activation.test.ts": 4596, - "packages/cli/tests/testing-execution-host.test.ts": 56559, - "packages/cli/tests/upgrade-cli.test.ts": 21067, - "packages/cli/tests/upgrade-command-document.test.ts": 7332, - "packages/cli/tests/upgrade-output.test.ts": 4599, - "packages/cli/tests/value-root.test.ts": 17482, - "packages/cli/tests/verbose-component.test.ts": 5046, - "packages/cli/tests/workflow-agent-sessions.test.ts": 19205, - "packages/cli/tests/workflow-agent.test.ts": 15879, - "packages/cli/tests/workflow-cli.test.ts": 108223, - "packages/cli/tests/workflow-crash.test.ts": 81045, - "packages/cli/tests/workflow-declaration.test.ts": 4494, - "packages/cli/tests/workflow-export-publication.test.ts": 17358, - "packages/cli/tests/workflow-fetch.test.ts": 8151, - "packages/cli/tests/workflow-fork.test.ts": 85702, - "packages/cli/tests/workflow-host.test.ts": 14581, - "packages/cli/tests/workflow-inspection.test.ts": 116193, - "packages/cli/tests/workflow-installation.test.ts": 6320, - "packages/cli/tests/workflow-lifecycle-control.test.ts": 20687, - "packages/cli/tests/workflow-retention.test.ts": 22913, - "packages/cli/tests/workflow-suspension.test.ts": 7981, - "packages/code-review-agent/tests/doctor.test.ts": 1540, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 1597, - "packages/code-review-agent/tests/parse-diff.test.ts": 1571, - "packages/code-review-agent/tests/parse-doctor.test.ts": 4103, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 1566, - "packages/code-review-agent/tests/policy.test.ts": 1556, - "packages/core/tests/agent-api.test.ts": 1576, - "packages/core/tests/agent-components.test.ts": 4731, - "packages/core/tests/agent-function-components.test.ts": 6430, - "packages/core/tests/agent-session-launch.test.ts": 6743, - "packages/core/tests/agent-session-placement.test.ts": 1607, - "packages/core/tests/agent-session-use-loaded-copy.test.ts": 1718, - "packages/core/tests/agent-session-use.test.ts": 1588, - "packages/core/tests/agent-stack.test.ts": 4270, - "packages/core/tests/answer-identity.test.ts": 3719, - "packages/core/tests/answers-component.test.ts": 4881, - "packages/core/tests/answers-expansion-recursion.test.ts": 3883, - "packages/core/tests/capture-errors.test.ts": 4117, - "packages/core/tests/capture-props.test.ts": 3922, - "packages/core/tests/cli-journal.test.ts": 12311, - "packages/core/tests/code-block-component.test.ts": 5440, - "packages/core/tests/compiler-boundary.test.ts": 3925, - "packages/core/tests/component-api.test.ts": 3668, - "packages/core/tests/component-registration.test.ts": 4720, - "packages/core/tests/component-returns.test.ts": 5150, - "packages/core/tests/component-schema-conformance.test.ts": 3996, - "packages/core/tests/config-api.test.ts": 4074, - "packages/core/tests/construct-error-observation.test.ts": 4166, - "packages/core/tests/contextual-cwd.test.ts": 5197, - "packages/core/tests/daemon-integration.test.ts": 4655, - "packages/core/tests/daemon.test.ts": 3729, - "packages/core/tests/declared-markdown-component.test.ts": 5441, - "packages/core/tests/document-output-api.test.ts": 1545, - "packages/core/tests/document-target-execution.test.ts": 6773, - "packages/core/tests/document-targets.test.ts": 4046, - "packages/core/tests/document-validation.test.ts": 5420, - "packages/core/tests/documentation-index.test.ts": 3727, - "packages/core/tests/each.test.ts": 4043, - "packages/core/tests/elicit-component.test.ts": 4583, - "packages/core/tests/ephemeral-service.test.ts": 4478, - "packages/core/tests/eval-bindings.test.ts": 3943, - "packages/core/tests/eval-context.test.ts": 2191, - "packages/core/tests/eval-durable.test.ts": 3995, - "packages/core/tests/eval-error-mode.test.ts": 4245, - "packages/core/tests/eval-interpolate.test.ts": 1534, - "packages/core/tests/eval-middleware.test.ts": 3662, - "packages/core/tests/eval-persist.test.ts": 4113, - "packages/core/tests/eval-return.test.ts": 4024, - "packages/core/tests/eval-scope.test.ts": 3917, - "packages/core/tests/eval-timeout.test.ts": 4025, - "packages/core/tests/eval-transform.test.ts": 3582, - "packages/core/tests/evaluate-component.test.ts": 5882, - "packages/core/tests/evaluate-loaded-copy.test.ts": 4011, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 4134, - "packages/core/tests/evaluation-profile.test.ts": 3805, - "packages/core/tests/exec-timeout.test.ts": 4106, - "packages/core/tests/execute.test.ts": 4636, - "packages/core/tests/execution-protocol.test.ts": 5358, - "packages/core/tests/expand.test.ts": 4719, - "packages/core/tests/expansion-identity.test.ts": 4585, - "packages/core/tests/expansion-metadata.test.ts": 3837, - "packages/core/tests/expression-props.test.ts": 4475, - "packages/core/tests/fail-component.test.ts": 4210, - "packages/core/tests/failure-printing.test.ts": 4239, - "packages/core/tests/fatal-cause.test.ts": 3750, - "packages/core/tests/fetch-component.test.ts": 5335, - "packages/core/tests/file-component.test.ts": 5869, - "packages/core/tests/file-delete-component.test.ts": 4128, - "packages/core/tests/files-fatal.test.ts": 4916, - "packages/core/tests/foreground-exec.test.ts": 5059, - "packages/core/tests/frontmatter.test.ts": 3629, - "packages/core/tests/function-components.test.ts": 4481, - "packages/core/tests/generated-composition.test.ts": 4481, - "packages/core/tests/generated-xmd.test.ts": 5791, - "packages/core/tests/glob-api.test.ts": 1898, - "packages/core/tests/glob-component.test.ts": 4625, - "packages/core/tests/guarded-journal.test.ts": 3945, - "packages/core/tests/has-content.test.ts": 3812, - "packages/core/tests/heal.test.ts": 3799, - "packages/core/tests/if.test.ts": 4449, - "packages/core/tests/inline-root.test.ts": 3986, - "packages/core/tests/invocation-failures.test.ts": 3705, - "packages/core/tests/invocation-identity.test.ts": 4403, - "packages/core/tests/invocation-scope.test.ts": 4078, - "packages/core/tests/journal-source-position.test.ts": 4195, - "packages/core/tests/json-component.test.ts": 4217, - "packages/core/tests/json.test.ts": 3606, - "packages/core/tests/let.test.ts": 4016, - "packages/core/tests/loaded-copy-files.test.ts": 3900, - "packages/core/tests/loop.test.ts": 4825, - "packages/core/tests/named-slots.test.ts": 4729, - "packages/core/tests/output-error-mode.test.ts": 5015, - "packages/core/tests/output-normalize.test.ts": 1545, - "packages/core/tests/output-terminal.test.ts": 1661, - "packages/core/tests/parse-components.test.ts": 4054, - "packages/core/tests/plan-response.test.ts": 1590, - "packages/core/tests/plugin-api.test.ts": 3570, - "packages/core/tests/plugin.test.ts": 3779, - "packages/core/tests/props-binding.test.ts": 4161, - "packages/core/tests/protected-content.test.ts": 3610, - "packages/core/tests/registered-printed-errors.test.ts": 3784, - "packages/core/tests/replay-stream.test.ts": 1575, - "packages/core/tests/retain.test.ts": 3987, - "packages/core/tests/root-composition.test.ts": 4067, - "packages/core/tests/root-props.test.ts": 4128, - "packages/core/tests/root-provider.test.ts": 4123, - "packages/core/tests/sample-component.test.ts": 4798, - "packages/core/tests/scanner.test.ts": 3617, - "packages/core/tests/scope-local.test.ts": 1526, - "packages/core/tests/secret-detection.test.ts": 4746, - "packages/core/tests/secret-files.test.ts": 2071, - "packages/core/tests/secret-rules.test.ts": 2055, - "packages/core/tests/secret-scanner-baseline.test.ts": 1753, - "packages/core/tests/secret-scanner.test.ts": 1903, - "packages/core/tests/source-position.test.ts": 3848, - "packages/core/tests/state-ownership.test.ts": 3814, - "packages/core/tests/streaming-emission.test.ts": 3810, - "packages/core/tests/switch.test.ts": 4503, - "packages/core/tests/syntax-catalog.test.ts": 4532, - "packages/core/tests/syntax-component.test.ts": 5259, - "packages/core/tests/syntax-loaded-copy.test.ts": 4023, - "packages/core/tests/temp-dir.test.ts": 6377, - "packages/core/tests/temp-file-compiler.test.ts": 2196, - "packages/core/tests/text-interpolation.test.ts": 3757, - "packages/core/tests/try-content.test.ts": 3793, - "packages/core/tests/unused-in-diff.test.ts": 4133, - "packages/core/tests/validate.test.ts": 3870, - "packages/core/tests/validation-integration.test.ts": 3900, - "packages/core/tests/workflow-component-bundle.test.ts": 4243, - "packages/durable-streams/tests/context.test.ts": 1809, - "packages/durable-streams/tests/deterministic-id.test.ts": 1863, - "packages/durable-streams/tests/divergence-api.test.ts": 1830, - "packages/durable-streams/tests/divergence.test.ts": 1908, - "packages/durable-streams/tests/durable-each.test.ts": 1894, - "packages/durable-streams/tests/durable-position.test.ts": 1812, - "packages/durable-streams/tests/durable-run.test.ts": 1886, - "packages/durable-streams/tests/ephemeral.test.ts": 1825, - "packages/durable-streams/tests/fail-stop.test.ts": 1874, - "packages/durable-streams/tests/guard-stream.test.ts": 1952, - "packages/durable-streams/tests/live-coordinator.test.ts": 1854, - "packages/durable-streams/tests/parse.test.ts": 1812, - "packages/durable-streams/tests/replay-guard.test.ts": 1923, - "packages/durable-streams/tests/replay-index.test.ts": 1619, - "packages/durable-streams/tests/retained.test.ts": 1664, - "packages/durable-streams/tests/serialize-event.test.ts": 1803, - "packages/durable-streams/tests/smoke.test.ts": 1780, - "packages/durable-streams/tests/structured-concurrency.test.ts": 1977, - "packages/durable-streams/tests/terminal-boundary.test.ts": 1892, - "packages/durable-streams/tests/types.test.ts": 1520, - "packages/git/tests/ambient-authentication.test.ts": 27034, - "packages/git/tests/api-entrypoint.test.ts": 5078, - "packages/git/tests/credential-helper.test.ts": 6204, - "packages/git/tests/git-add-crash.test.ts": 7227, - "packages/git/tests/git-add-durability.test.ts": 26695, - "packages/git/tests/git-add.test.ts": 35508, - "packages/git/tests/git-commit-crash.test.ts": 7481, - "packages/git/tests/git-commit-durability.test.ts": 34971, - "packages/git/tests/git-commit.test.ts": 41874, - "packages/git/tests/git-host-effect.test.ts": 9161, - "packages/git/tests/git-push-crash.test.ts": 10272, - "packages/git/tests/git-push-durability.test.ts": 44877, - "packages/git/tests/git-push.test.ts": 53878, - "packages/git/tests/git-switch-crash.test.ts": 7271, - "packages/git/tests/git-switch-durability.test.ts": 22118, - "packages/git/tests/git-switch.test.ts": 23370, - "packages/git/tests/git.test.ts": 4434, - "packages/git/tests/github-activation.test.ts": 5703, - "packages/git/tests/github-issues.test.ts": 4432, - "packages/git/tests/github-pull-requests.test.ts": 4086, - "packages/git/tests/github-workflow-activation.test.ts": 6012, - "packages/git/tests/issue-markdown.test.ts": 11443, - "packages/git/tests/issue-records.test.ts": 4436, - "packages/git/tests/materialization.test.ts": 5130, - "packages/git/tests/module-partition.test.ts": 5472, - "packages/git/tests/plugin.test.ts": 4812, - "packages/git/tests/provider-neutrality.test.ts": 3598, - "packages/git/tests/public-entrypoint.test.ts": 9766, - "packages/git/tests/pull-request-crash.test.ts": 8575, - "packages/git/tests/pull-request-durability.test.ts": 42850, - "packages/git/tests/pull-request-read.test.ts": 8277, - "packages/git/tests/pull-request-records.test.ts": 4350, - "packages/git/tests/pull-request.test.ts": 73466, - "packages/git/tests/repository-components.test.ts": 12917, - "packages/git/tests/repository-control-plane.test.ts": 11733, - "packages/git/tests/repository-materialization.test.ts": 8745, - "packages/git/tests/repository-replay.test.ts": 16106, - "packages/git/tests/repository-storage.test.ts": 20115, - "packages/git/tests/run-composition-ambient.test.ts": 13438, - "packages/git/tests/run-composition-lazy.test.ts": 5937, - "packages/git/tests/run-composition-managed.test.ts": 15140, - "packages/git/tests/run-composition-remote.test.ts": 15293, - "packages/git/tests/selection-authentication.test.ts": 1841, - "packages/git/tests/worktree-replay.test.ts": 6981, - "packages/runtime/tests/agent-session-coordinator.test.ts": 2234, - "packages/runtime/tests/duration.test.ts": 1545, - "packages/runtime/tests/executable-observer.test.ts": 1928, - "packages/runtime/tests/fetch.test.ts": 2383, - "packages/runtime/tests/fs.test.ts": 1733, - "packages/runtime/tests/host-files.test.ts": 2589, - "packages/runtime/tests/native-launcher.test.ts": 3955, - "packages/runtime/tests/process.test.ts": 1740, - "packages/runtime/tests/service.test.ts": 1849, - "packages/test-agent/tests/acp-server.test.ts": 1719, - "packages/test-agent/tests/behavior-engine.test.ts": 4298, - "packages/test-agent/tests/bridge.test.ts": 3716, - "packages/test-agent/tests/command-lazy.test.ts": 8032, - "packages/test-agent/tests/components.test.ts": 61791, - "packages/test-agent/tests/controller.test.ts": 2881, - "packages/test-agent/tests/cross-package-resolution.test.ts": 6157, - "packages/test-agent/tests/native-launch.test.ts": 30913, - "packages/test-agent/tests/net.test.ts": 1613, - "packages/test-agent/tests/profile.test.ts": 4043, - "packages/test-agent/tests/protocol.test.ts": 2443, - "packages/test-agent/tests/provider.test.ts": 4376, - "packages/test-agent/tests/public-api.test.ts": 5102, - "packages/test-agent/tests/route-slot.test.ts": 1527, - "packages/test-agent/tests/smoke.test.ts": 21250, - "packages/test-agent/tests/template.test.ts": 4007, - "packages/test-agent/tests/worker-lifecycle.test.ts": 13359, - "packages/test-support/tests/journal.test.ts": 1846, - "packages/testing/tests/agent-composition.test.ts": 4367, - "packages/testing/tests/assert-throws.test.ts": 5605, - "packages/testing/tests/assert.test.ts": 1565, - "packages/testing/tests/assertions.test.ts": 6194, - "packages/testing/tests/boundary-contract.test.ts": 5041, - "packages/testing/tests/cli.test.ts": 6822, - "packages/testing/tests/execution-harness.test.ts": 8902, - "packages/testing/tests/replay.test.ts": 5555, - "packages/testing/tests/smoke.test.ts": 5707, - "packages/testing/tests/test-component.test.ts": 6164, - "packages/testing/tests/testing-activation.test.ts": 5833, - "packages/testing/tests/testing-boundary.test.ts": 4698, - "packages/testing/tests/testing-mode.test.ts": 6306, - "packages/testing/tests/use-testing.test.ts": 5192, - "packages/web/tests/assets.test.ts": 1596, - "packages/web/tests/client-logic.test.ts": 1649, - "packages/web/tests/compile.test.ts": 4674, - "packages/web/tests/component.test.ts": 5194, - "packages/web/tests/declaration.test.ts": 4460, - "packages/web/tests/document.test.ts": 4731, - "packages/web/tests/elicitation.test.ts": 4488, - "packages/web/tests/live-form.test.ts": 4360, - "packages/web/tests/markdown.test.ts": 1790, - "packages/web/tests/opener.test.ts": 4349, - "packages/web/tests/page.test.ts": 1575, - "packages/web/tests/responder.test.ts": 4637, - "packages/web/tests/server-lifecycle.test.ts": 4495, - "packages/web/tests/server.test.ts": 4765, - "packages/workflow/tests/generated-agent-component.test.ts": 6806, - "packages/workflow/tests/generated-observations.test.ts": 4144, - "packages/workflow/tests/public-entrypoint.test.ts": 5919, - "packages/workflow/tests/retained-run.test.ts": 5048, - "packages/workflow/tests/service-denial.test.ts": 1865, - "packages/workflow/tests/workflow-agent-checkpoints.test.ts": 6099, - "packages/workflow/tests/workflow-agent-sessions.test.ts": 5001, - "packages/workflow/tests/workflow-bundle.test.ts": 4467, - "packages/workflow/tests/workflow-checkpoint.test.ts": 6174, - "packages/workflow/tests/workflow-definition.test.ts": 4212, - "packages/workflow/tests/workflow-export.test.ts": 8073, - "packages/workflow/tests/workflow-fork-source.test.ts": 5140, - "packages/workflow/tests/workflow-fork.test.ts": 4118, - "packages/workflow/tests/workflow-lifecycle-authority.test.ts": 6062, - "packages/workflow/tests/workflow-lifecycle-control.test.ts": 6723, - "packages/workflow/tests/workflow-lifecycle-inspection.test.ts": 11202, - "packages/workflow/tests/workflow-run-journal.test.ts": 7244, - "packages/workflow/tests/workflow-run-storage.test.ts": 8184, - "packages/workflow/tests/workflow-run.test.ts": 4985, - "packages/workflow/tests/workflow-suspension-answer.test.ts": 6002, - "packages/workflow/tests/workflow-suspension.test.ts": 5685, - "packages/workflow/tests/workspace-crash-recovery.test.ts": 7784, - "packages/workflow/tests/workspace-effect-loaded-copy.test.ts": 5102, - "packages/workflow/tests/workspace-effect-transaction.test.ts": 5918, - "packages/workflow/tests/workspace-effect.test.ts": 6014, - "packages/workflow/tests/workspace-files.test.ts": 12933, - "packages/workflow/tests/workspace-root-restoration.test.ts": 6760, - "packages/workflow/tests/workspace-root.test.ts": 5094, - "packages/workflow/tests/workspace-transaction.test.ts": 5097, - "packages/workflow/tests/xmd-artifact.test.ts": 6972, - "scripts/tests/acpx-vendor.test.ts": 2160, - "scripts/tests/adapter-distribution.test.ts": 4586, - "scripts/tests/adapter-npm-package.test.ts": 29243, - "scripts/tests/adapter-vendor.test.ts": 4198, - "scripts/tests/bootstrap-npm-package.test.ts": 11443, - "scripts/tests/build-npm.test.ts": 40709, - "scripts/tests/build-web-client.test.ts": 30613, - "scripts/tests/bump-version.test.ts": 1659, - "scripts/tests/changed-paths.test.ts": 1583, - "scripts/tests/ci-workflow.test.ts": 4871, - "scripts/tests/cli-npm-bin.test.ts": 252922, - "scripts/tests/cloudflare-dofs-vendor.test.ts": 4431, - "scripts/tests/consumer-cycle.test.ts": 1661, - "scripts/tests/documentation-validation.test.ts": 6267, - "scripts/tests/filesystem-contract-workflow.test.ts": 1572, - "scripts/tests/frozen-entry.test.ts": 7664, - "scripts/tests/jsr-consumer-documentation.test.ts": 18170, - "scripts/tests/main-green.test.ts": 1936, - "scripts/tests/main-health.test.ts": 1715, - "scripts/tests/measure-test-weights.test.ts": 1992, - "scripts/tests/no-module-scoped-registry.test.ts": 2370, - "scripts/tests/no-redundant-test-scope.test.ts": 6520, - "scripts/tests/no-sync-filesystem.test.ts": 6462, - "scripts/tests/no-yield-in-finally.test.ts": 2377, - "scripts/tests/oxlint-policy.test.ts": 12237, - "scripts/tests/packaged-document.test.ts": 1618, - "scripts/tests/prefer-effection-operation.test.ts": 7468, - "scripts/tests/prefer-effection-result.test.ts": 5680, - "scripts/tests/prepared-state.test.ts": 2853, - "scripts/tests/publish-workflow-generator.test.ts": 6220, - "scripts/tests/publish-workflow-membership.test.ts": 1734, - "scripts/tests/publishable-membership-agreement.test.ts": 4083, - "scripts/tests/readme-targets.test.ts": 18898, - "scripts/tests/release-targets.test.ts": 1695, - "scripts/tests/review-infrastructure.test.ts": 6279, - "scripts/tests/runtime-exclusions.test.ts": 2097, - "scripts/tests/runtime-tests.test.ts": 1686, - "scripts/tests/scope-bound-event-registration.test.ts": 6340, - "scripts/tests/shard-execution.test.ts": 11463, - "scripts/tests/staged-write.test.ts": 1604, - "scripts/tests/test-file-discovery.test.ts": 1840, - "scripts/tests/test-shards.test.ts": 1619, - "scripts/tests/test-weights.test.ts": 1864, - "scripts/tests/tracked.test.ts": 1585, - "scripts/tests/verify-adapter.test.ts": 7915, - "scripts/tests/verify-clean.test.ts": 1806, - "scripts/tests/verify-coordinator.test.ts": 1992, - "scripts/tests/version-lockstep.test.ts": 1782, - "scripts/tests/web-client-module.test.ts": 1570, - "scripts/tests/workspace.test.ts": 1581 + "packages/acp/tests/acceptance.test.ts": 5139, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 8515, + "packages/acp/tests/acpx-materialization.test.ts": 8150, + "packages/acp/tests/acpx-transient-env.test.ts": 1821, + "packages/acp/tests/adapter-materialization.test.ts": 78988, + "packages/acp/tests/adapter-protocol.test.ts": 61601, + "packages/acp/tests/codex-surfaces.test.ts": 1833, + "packages/acp/tests/loaded-copy.test.ts": 4786, + "packages/acp/tests/native-launch.test.ts": 5474, + "packages/acp/tests/permission-bridge.test.ts": 4275, + "packages/acp/tests/provider.test.ts": 5379, + "packages/acp/tests/serial-queue.test.ts": 1623, + "packages/acp/tests/session-key.test.ts": 4052, + "packages/acp/tests/session-route.test.ts": 4267, + "packages/acp/tests/terminal-screen.test.ts": 1764, + "packages/cli/tests/agent-adapters.test.ts": 5788, + "packages/cli/tests/agent-cli.test.ts": 38729, + "packages/cli/tests/agent-config.test.ts": 3784, + "packages/cli/tests/agent-options-cli.test.ts": 15983, + "packages/cli/tests/agent-options.test.ts": 3813, + "packages/cli/tests/agent-session-coordinator.test.ts": 4499, + "packages/cli/tests/cli-help.test.ts": 20957, + "packages/cli/tests/command.test.ts": 10570, + "packages/cli/tests/compiled-upgrade.test.ts": 11276, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 9268, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 122402, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 8908, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 12657, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 10782, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 15941, + "packages/cli/tests/evaluate-component.test.ts": 12222, + "packages/cli/tests/evaluate-workflow.test.ts": 5866, + "packages/cli/tests/fetch-cli.test.ts": 3906, + "packages/cli/tests/file-stream.test.ts": 1856, + "packages/cli/tests/github-zero-effect.test.ts": 7422, + "packages/cli/tests/inline-cli.test.ts": 34156, + "packages/cli/tests/launch-timeout.test.ts": 11644, + "packages/cli/tests/packaged-document.test.ts": 5037, + "packages/cli/tests/plan-args.test.ts": 1582, + "packages/cli/tests/plan-cli.test.ts": 102307, + "packages/cli/tests/plan-command-document.test.ts": 10266, + "packages/cli/tests/plan-component.test.ts": 12588, + "packages/cli/tests/plan-host-acts.test.ts": 5568, + "packages/cli/tests/plan.test.ts": 16769, + "packages/cli/tests/plugin-cli.test.ts": 41879, + "packages/cli/tests/plugin-host.test.ts": 6332, + "packages/cli/tests/plugin-modules.test.ts": 1556, + "packages/cli/tests/plugin-selection.test.ts": 1561, + "packages/cli/tests/process-retention.test.ts": 5510, + "packages/cli/tests/props-cli.test.ts": 31508, + "packages/cli/tests/props-schema.test.ts": 4225, + "packages/cli/tests/props-sources.test.ts": 2454, + "packages/cli/tests/pull-request-read-fork.test.ts": 7419, + "packages/cli/tests/repl-boundaries.test.ts": 7821, + "packages/cli/tests/repl-composition.test.ts": 2141, + "packages/cli/tests/repl-execution.test.ts": 5669, + "packages/cli/tests/repl-journey.test.ts": 20829, + "packages/cli/tests/repl-model.test.ts": 5524, + "packages/cli/tests/repl-route.test.ts": 5007, + "packages/cli/tests/repl-terminal.test.ts": 2992, + "packages/cli/tests/run-composition-deno.test.ts": 8299, + "packages/cli/tests/run-composition-nested.test.ts": 21878, + "packages/cli/tests/run-composition.test.ts": 7301, + "packages/cli/tests/run-deadline.test.ts": 9041, + "packages/cli/tests/run-profile.test.ts": 4530, + "packages/cli/tests/run-timeouts.test.ts": 13412, + "packages/cli/tests/secret-detection-cli.test.ts": 20200, + "packages/cli/tests/service-document.test.ts": 5466, + "packages/cli/tests/service-host.test.ts": 5372, + "packages/cli/tests/session-launch-cli.test.ts": 10990, + "packages/cli/tests/stdin-cli.test.ts": 38532, + "packages/cli/tests/stdout-delivery.test.ts": 1616, + "packages/cli/tests/syntax-cli.test.ts": 37953, + "packages/cli/tests/targets-cli.test.ts": 30055, + "packages/cli/tests/test-root-profile.test.ts": 7519, + "packages/cli/tests/test-target.test.ts": 38653, + "packages/cli/tests/testing-activation.test.ts": 4672, + "packages/cli/tests/testing-execution-host.test.ts": 58524, + "packages/cli/tests/upgrade-cli.test.ts": 21591, + "packages/cli/tests/upgrade-command-document.test.ts": 7600, + "packages/cli/tests/upgrade-output.test.ts": 4756, + "packages/cli/tests/value-root.test.ts": 18176, + "packages/cli/tests/verbose-component.test.ts": 5065, + "packages/cli/tests/workflow-agent-sessions.test.ts": 20012, + "packages/cli/tests/workflow-agent.test.ts": 16243, + "packages/cli/tests/workflow-cli.test.ts": 110048, + "packages/cli/tests/workflow-crash.test.ts": 81682, + "packages/cli/tests/workflow-declaration.test.ts": 4738, + "packages/cli/tests/workflow-export-publication.test.ts": 18109, + "packages/cli/tests/workflow-fetch.test.ts": 8495, + "packages/cli/tests/workflow-fork.test.ts": 89126, + "packages/cli/tests/workflow-host.test.ts": 15299, + "packages/cli/tests/workflow-inspection.test.ts": 121028, + "packages/cli/tests/workflow-installation.test.ts": 6511, + "packages/cli/tests/workflow-lifecycle-control.test.ts": 21497, + "packages/cli/tests/workflow-retention.test.ts": 24271, + "packages/cli/tests/workflow-suspension.test.ts": 8453, + "packages/code-review-agent/tests/doctor.test.ts": 1592, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 1690, + "packages/code-review-agent/tests/parse-diff.test.ts": 1609, + "packages/code-review-agent/tests/parse-doctor.test.ts": 4194, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 1592, + "packages/code-review-agent/tests/policy.test.ts": 1583, + "packages/core/tests/agent-api.test.ts": 1621, + "packages/core/tests/agent-components.test.ts": 4835, + "packages/core/tests/agent-function-components.test.ts": 6755, + "packages/core/tests/agent-session-launch.test.ts": 7039, + "packages/core/tests/agent-session-placement.test.ts": 1664, + "packages/core/tests/agent-session-use-loaded-copy.test.ts": 1701, + "packages/core/tests/agent-session-use.test.ts": 1642, + "packages/core/tests/agent-stack.test.ts": 4370, + "packages/core/tests/all.test.ts": 5461, + "packages/core/tests/answer-identity.test.ts": 3824, + "packages/core/tests/answers-component.test.ts": 5020, + "packages/core/tests/answers-expansion-recursion.test.ts": 3970, + "packages/core/tests/capture-errors.test.ts": 4234, + "packages/core/tests/capture-props.test.ts": 4093, + "packages/core/tests/cli-journal.test.ts": 12679, + "packages/core/tests/code-block-component.test.ts": 5603, + "packages/core/tests/compiler-boundary.test.ts": 4006, + "packages/core/tests/component-api.test.ts": 3752, + "packages/core/tests/component-registration.test.ts": 4910, + "packages/core/tests/component-returns.test.ts": 5391, + "packages/core/tests/component-schema-conformance.test.ts": 4169, + "packages/core/tests/config-api.test.ts": 4185, + "packages/core/tests/construct-error-observation.test.ts": 4314, + "packages/core/tests/contextual-cwd.test.ts": 5334, + "packages/core/tests/daemon-integration.test.ts": 4811, + "packages/core/tests/daemon.test.ts": 3803, + "packages/core/tests/declared-markdown-component.test.ts": 5582, + "packages/core/tests/document-output-api.test.ts": 1607, + "packages/core/tests/document-target-execution.test.ts": 7060, + "packages/core/tests/document-targets.test.ts": 4228, + "packages/core/tests/document-validation.test.ts": 5698, + "packages/core/tests/documentation-index.test.ts": 3845, + "packages/core/tests/each.test.ts": 4277, + "packages/core/tests/elicit-component.test.ts": 4768, + "packages/core/tests/ephemeral-service.test.ts": 4641, + "packages/core/tests/eval-bindings.test.ts": 4120, + "packages/core/tests/eval-context.test.ts": 2287, + "packages/core/tests/eval-durable.test.ts": 4160, + "packages/core/tests/eval-error-mode.test.ts": 4464, + "packages/core/tests/eval-interpolate.test.ts": 1560, + "packages/core/tests/eval-middleware.test.ts": 3769, + "packages/core/tests/eval-persist.test.ts": 4280, + "packages/core/tests/eval-return.test.ts": 4150, + "packages/core/tests/eval-scope.test.ts": 4142, + "packages/core/tests/eval-timeout.test.ts": 4131, + "packages/core/tests/eval-transform.test.ts": 3814, + "packages/core/tests/evaluate-component.test.ts": 6263, + "packages/core/tests/evaluate-loaded-copy.test.ts": 4282, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 4287, + "packages/core/tests/evaluation-profile.test.ts": 3859, + "packages/core/tests/exec-timeout.test.ts": 4191, + "packages/core/tests/execute.test.ts": 4727, + "packages/core/tests/execution-protocol.test.ts": 5587, + "packages/core/tests/expand.test.ts": 4965, + "packages/core/tests/expansion-identity.test.ts": 4799, + "packages/core/tests/expansion-metadata.test.ts": 4095, + "packages/core/tests/expression-props.test.ts": 4719, + "packages/core/tests/fail-component.test.ts": 4384, + "packages/core/tests/failure-printing.test.ts": 4361, + "packages/core/tests/fatal-cause.test.ts": 3923, + "packages/core/tests/fetch-component.test.ts": 5500, + "packages/core/tests/file-component.test.ts": 5958, + "packages/core/tests/file-delete-component.test.ts": 4211, + "packages/core/tests/files-fatal.test.ts": 4941, + "packages/core/tests/foreground-exec.test.ts": 5001, + "packages/core/tests/frontmatter.test.ts": 3665, + "packages/core/tests/function-components.test.ts": 4580, + "packages/core/tests/generated-composition.test.ts": 4553, + "packages/core/tests/generated-xmd.test.ts": 6067, + "packages/core/tests/glob-api.test.ts": 1918, + "packages/core/tests/glob-component.test.ts": 4672, + "packages/core/tests/guarded-journal.test.ts": 4010, + "packages/core/tests/has-content.test.ts": 3801, + "packages/core/tests/heal.test.ts": 3773, + "packages/core/tests/if.test.ts": 4496, + "packages/core/tests/inline-root.test.ts": 4020, + "packages/core/tests/invocation-failures.test.ts": 3737, + "packages/core/tests/invocation-identity.test.ts": 4464, + "packages/core/tests/invocation-scope.test.ts": 4005, + "packages/core/tests/journal-source-position.test.ts": 4210, + "packages/core/tests/json-component.test.ts": 4212, + "packages/core/tests/json.test.ts": 3675, + "packages/core/tests/let.test.ts": 4065, + "packages/core/tests/loaded-copy-files.test.ts": 3964, + "packages/core/tests/loop.test.ts": 4860, + "packages/core/tests/named-slots.test.ts": 4848, + "packages/core/tests/output-error-mode.test.ts": 5081, + "packages/core/tests/output-normalize.test.ts": 1533, + "packages/core/tests/output-terminal.test.ts": 1667, + "packages/core/tests/parse-components.test.ts": 4165, + "packages/core/tests/plan-response.test.ts": 1584, + "packages/core/tests/plugin-api.test.ts": 3605, + "packages/core/tests/plugin.test.ts": 3814, + "packages/core/tests/props-binding.test.ts": 4146, + "packages/core/tests/protected-content.test.ts": 3613, + "packages/core/tests/registered-printed-errors.test.ts": 3833, + "packages/core/tests/replay-stream.test.ts": 1542, + "packages/core/tests/retain.test.ts": 3994, + "packages/core/tests/root-composition.test.ts": 4156, + "packages/core/tests/root-props.test.ts": 4098, + "packages/core/tests/root-provider.test.ts": 4171, + "packages/core/tests/sample-component.test.ts": 4864, + "packages/core/tests/scanner.test.ts": 3655, + "packages/core/tests/scope-local.test.ts": 1562, + "packages/core/tests/secret-detection.test.ts": 4896, + "packages/core/tests/secret-files.test.ts": 2079, + "packages/core/tests/secret-rules.test.ts": 2080, + "packages/core/tests/secret-scanner-baseline.test.ts": 1750, + "packages/core/tests/secret-scanner.test.ts": 1923, + "packages/core/tests/source-position.test.ts": 3948, + "packages/core/tests/state-ownership.test.ts": 3981, + "packages/core/tests/streaming-emission.test.ts": 3980, + "packages/core/tests/switch.test.ts": 4647, + "packages/core/tests/syntax-catalog.test.ts": 4755, + "packages/core/tests/syntax-component.test.ts": 5476, + "packages/core/tests/syntax-loaded-copy.test.ts": 4125, + "packages/core/tests/temp-dir.test.ts": 6491, + "packages/core/tests/temp-file-compiler.test.ts": 2234, + "packages/core/tests/text-interpolation.test.ts": 3885, + "packages/core/tests/try-content.test.ts": 3827, + "packages/core/tests/unused-in-diff.test.ts": 4144, + "packages/core/tests/validate.test.ts": 3881, + "packages/core/tests/validation-integration.test.ts": 4029, + "packages/core/tests/workflow-component-bundle.test.ts": 4296, + "packages/durable-streams/tests/context.test.ts": 1828, + "packages/durable-streams/tests/deterministic-id.test.ts": 1872, + "packages/durable-streams/tests/divergence-api.test.ts": 1833, + "packages/durable-streams/tests/divergence.test.ts": 1910, + "packages/durable-streams/tests/durable-each.test.ts": 1908, + "packages/durable-streams/tests/durable-position.test.ts": 1868, + "packages/durable-streams/tests/durable-run.test.ts": 1897, + "packages/durable-streams/tests/ephemeral.test.ts": 1875, + "packages/durable-streams/tests/fail-stop.test.ts": 1903, + "packages/durable-streams/tests/guard-stream.test.ts": 1935, + "packages/durable-streams/tests/live-coordinator.test.ts": 1864, + "packages/durable-streams/tests/parse.test.ts": 1844, + "packages/durable-streams/tests/replay-guard.test.ts": 1973, + "packages/durable-streams/tests/replay-index.test.ts": 1667, + "packages/durable-streams/tests/retained.test.ts": 1767, + "packages/durable-streams/tests/serialize-event.test.ts": 1853, + "packages/durable-streams/tests/smoke.test.ts": 1847, + "packages/durable-streams/tests/structured-concurrency.test.ts": 1960, + "packages/durable-streams/tests/terminal-boundary.test.ts": 1913, + "packages/durable-streams/tests/types.test.ts": 1500, + "packages/git/tests/ambient-authentication.test.ts": 27928, + "packages/git/tests/api-entrypoint.test.ts": 5273, + "packages/git/tests/credential-helper.test.ts": 6302, + "packages/git/tests/git-add-crash.test.ts": 7199, + "packages/git/tests/git-add-durability.test.ts": 28169, + "packages/git/tests/git-add.test.ts": 37551, + "packages/git/tests/git-commit-crash.test.ts": 7598, + "packages/git/tests/git-commit-durability.test.ts": 35375, + "packages/git/tests/git-commit.test.ts": 43544, + "packages/git/tests/git-host-effect.test.ts": 9220, + "packages/git/tests/git-push-crash.test.ts": 10522, + "packages/git/tests/git-push-durability.test.ts": 47327, + "packages/git/tests/git-push.test.ts": 53042, + "packages/git/tests/git-switch-crash.test.ts": 7169, + "packages/git/tests/git-switch-durability.test.ts": 22374, + "packages/git/tests/git-switch.test.ts": 23500, + "packages/git/tests/git.test.ts": 4462, + "packages/git/tests/github-activation.test.ts": 5728, + "packages/git/tests/github-issues.test.ts": 4392, + "packages/git/tests/github-pull-requests.test.ts": 4024, + "packages/git/tests/github-workflow-activation.test.ts": 6038, + "packages/git/tests/issue-markdown.test.ts": 11613, + "packages/git/tests/issue-records.test.ts": 4343, + "packages/git/tests/materialization.test.ts": 5083, + "packages/git/tests/module-partition.test.ts": 5406, + "packages/git/tests/plugin.test.ts": 4764, + "packages/git/tests/provider-neutrality.test.ts": 3523, + "packages/git/tests/public-entrypoint.test.ts": 9694, + "packages/git/tests/pull-request-crash.test.ts": 8613, + "packages/git/tests/pull-request-durability.test.ts": 42143, + "packages/git/tests/pull-request-read.test.ts": 8263, + "packages/git/tests/pull-request-records.test.ts": 4320, + "packages/git/tests/pull-request.test.ts": 74015, + "packages/git/tests/repository-components.test.ts": 13059, + "packages/git/tests/repository-control-plane.test.ts": 11699, + "packages/git/tests/repository-materialization.test.ts": 8691, + "packages/git/tests/repository-replay.test.ts": 16427, + "packages/git/tests/repository-storage.test.ts": 20373, + "packages/git/tests/run-composition-ambient.test.ts": 13487, + "packages/git/tests/run-composition-lazy.test.ts": 5943, + "packages/git/tests/run-composition-managed.test.ts": 15967, + "packages/git/tests/run-composition-remote.test.ts": 16212, + "packages/git/tests/selection-authentication.test.ts": 1889, + "packages/git/tests/worktree-replay.test.ts": 7287, + "packages/runtime/tests/agent-session-coordinator.test.ts": 2293, + "packages/runtime/tests/duration.test.ts": 1569, + "packages/runtime/tests/executable-observer.test.ts": 1971, + "packages/runtime/tests/fetch.test.ts": 2451, + "packages/runtime/tests/fs.test.ts": 1767, + "packages/runtime/tests/host-files.test.ts": 2621, + "packages/runtime/tests/native-launcher.test.ts": 4020, + "packages/runtime/tests/process.test.ts": 1791, + "packages/runtime/tests/service.test.ts": 1906, + "packages/test-agent/tests/acp-server.test.ts": 1738, + "packages/test-agent/tests/behavior-engine.test.ts": 4396, + "packages/test-agent/tests/bridge.test.ts": 3921, + "packages/test-agent/tests/command-lazy.test.ts": 8254, + "packages/test-agent/tests/components.test.ts": 63092, + "packages/test-agent/tests/controller.test.ts": 3051, + "packages/test-agent/tests/cross-package-resolution.test.ts": 6405, + "packages/test-agent/tests/native-launch.test.ts": 32011, + "packages/test-agent/tests/net.test.ts": 1659, + "packages/test-agent/tests/profile.test.ts": 4172, + "packages/test-agent/tests/protocol.test.ts": 2553, + "packages/test-agent/tests/provider.test.ts": 4566, + "packages/test-agent/tests/public-api.test.ts": 5254, + "packages/test-agent/tests/route-slot.test.ts": 1621, + "packages/test-agent/tests/smoke.test.ts": 21659, + "packages/test-agent/tests/template.test.ts": 4152, + "packages/test-agent/tests/worker-lifecycle.test.ts": 13928, + "packages/test-support/tests/journal.test.ts": 1902, + "packages/testing/tests/agent-composition.test.ts": 4483, + "packages/testing/tests/assert-throws.test.ts": 5864, + "packages/testing/tests/assert.test.ts": 1572, + "packages/testing/tests/assertions.test.ts": 6323, + "packages/testing/tests/boundary-contract.test.ts": 5297, + "packages/testing/tests/cli.test.ts": 7146, + "packages/testing/tests/execution-harness.test.ts": 9300, + "packages/testing/tests/replay.test.ts": 5798, + "packages/testing/tests/smoke.test.ts": 5991, + "packages/testing/tests/test-component.test.ts": 6419, + "packages/testing/tests/testing-activation.test.ts": 6036, + "packages/testing/tests/testing-boundary.test.ts": 4938, + "packages/testing/tests/testing-mode.test.ts": 6447, + "packages/testing/tests/use-testing.test.ts": 5495, + "packages/web/tests/assets.test.ts": 1693, + "packages/web/tests/client-logic.test.ts": 1668, + "packages/web/tests/compile.test.ts": 4897, + "packages/web/tests/component.test.ts": 5479, + "packages/web/tests/declaration.test.ts": 4662, + "packages/web/tests/document.test.ts": 5014, + "packages/web/tests/elicitation.test.ts": 4650, + "packages/web/tests/live-form.test.ts": 4546, + "packages/web/tests/markdown.test.ts": 1815, + "packages/web/tests/opener.test.ts": 4579, + "packages/web/tests/page.test.ts": 1635, + "packages/web/tests/responder.test.ts": 4831, + "packages/web/tests/server-lifecycle.test.ts": 4664, + "packages/web/tests/server.test.ts": 4997, + "packages/workflow/tests/generated-agent-component.test.ts": 7215, + "packages/workflow/tests/generated-observations.test.ts": 4282, + "packages/workflow/tests/public-entrypoint.test.ts": 6231, + "packages/workflow/tests/retained-run.test.ts": 5131, + "packages/workflow/tests/service-denial.test.ts": 1846, + "packages/workflow/tests/workflow-agent-checkpoints.test.ts": 6138, + "packages/workflow/tests/workflow-agent-sessions.test.ts": 5087, + "packages/workflow/tests/workflow-bundle.test.ts": 4470, + "packages/workflow/tests/workflow-checkpoint.test.ts": 6169, + "packages/workflow/tests/workflow-definition.test.ts": 4316, + "packages/workflow/tests/workflow-export.test.ts": 8206, + "packages/workflow/tests/workflow-fork-source.test.ts": 5146, + "packages/workflow/tests/workflow-fork.test.ts": 4139, + "packages/workflow/tests/workflow-lifecycle-authority.test.ts": 6080, + "packages/workflow/tests/workflow-lifecycle-control.test.ts": 6693, + "packages/workflow/tests/workflow-lifecycle-inspection.test.ts": 11366, + "packages/workflow/tests/workflow-run-journal.test.ts": 7255, + "packages/workflow/tests/workflow-run-storage.test.ts": 8326, + "packages/workflow/tests/workflow-run.test.ts": 5036, + "packages/workflow/tests/workflow-suspension-answer.test.ts": 6020, + "packages/workflow/tests/workflow-suspension.test.ts": 5656, + "packages/workflow/tests/workspace-crash-recovery.test.ts": 8091, + "packages/workflow/tests/workspace-effect-loaded-copy.test.ts": 5202, + "packages/workflow/tests/workspace-effect-transaction.test.ts": 6074, + "packages/workflow/tests/workspace-effect.test.ts": 5994, + "packages/workflow/tests/workspace-files.test.ts": 13129, + "packages/workflow/tests/workspace-root-restoration.test.ts": 6777, + "packages/workflow/tests/workspace-root.test.ts": 5179, + "packages/workflow/tests/workspace-transaction.test.ts": 5177, + "packages/workflow/tests/xmd-artifact.test.ts": 6999, + "scripts/tests/acpx-vendor.test.ts": 2129, + "scripts/tests/adapter-distribution.test.ts": 4591, + "scripts/tests/adapter-npm-package.test.ts": 34653, + "scripts/tests/adapter-vendor.test.ts": 4109, + "scripts/tests/bootstrap-npm-package.test.ts": 11757, + "scripts/tests/build-npm.test.ts": 42015, + "scripts/tests/build-web-client.test.ts": 31713, + "scripts/tests/bump-version.test.ts": 1674, + "scripts/tests/changed-paths.test.ts": 1567, + "scripts/tests/ci-workflow.test.ts": 4994, + "scripts/tests/cli-npm-bin.test.ts": 262615, + "scripts/tests/cloudflare-dofs-vendor.test.ts": 4432, + "scripts/tests/consumer-cycle.test.ts": 1675, + "scripts/tests/documentation-validation.test.ts": 6375, + "scripts/tests/filesystem-contract-workflow.test.ts": 1599, + "scripts/tests/frozen-entry.test.ts": 7979, + "scripts/tests/jsr-consumer-documentation.test.ts": 18585, + "scripts/tests/main-green.test.ts": 1929, + "scripts/tests/main-health.test.ts": 1746, + "scripts/tests/measure-test-weights.test.ts": 2021, + "scripts/tests/no-module-scoped-registry.test.ts": 2418, + "scripts/tests/no-redundant-test-scope.test.ts": 6617, + "scripts/tests/no-sync-filesystem.test.ts": 6464, + "scripts/tests/no-yield-in-finally.test.ts": 2410, + "scripts/tests/oxlint-policy.test.ts": 12273, + "scripts/tests/packaged-document.test.ts": 1632, + "scripts/tests/prefer-effection-operation.test.ts": 7621, + "scripts/tests/prefer-effection-result.test.ts": 5722, + "scripts/tests/prepared-state.test.ts": 2780, + "scripts/tests/publish-workflow-generator.test.ts": 6190, + "scripts/tests/publish-workflow-membership.test.ts": 1732, + "scripts/tests/publishable-membership-agreement.test.ts": 4098, + "scripts/tests/readme-targets.test.ts": 19003, + "scripts/tests/release-targets.test.ts": 1621, + "scripts/tests/review-infrastructure.test.ts": 6242, + "scripts/tests/runtime-exclusions.test.ts": 2055, + "scripts/tests/runtime-tests.test.ts": 1690, + "scripts/tests/scope-bound-event-registration.test.ts": 6271, + "scripts/tests/shard-execution.test.ts": 11427, + "scripts/tests/staged-write.test.ts": 1561, + "scripts/tests/test-file-discovery.test.ts": 1835, + "scripts/tests/test-shards.test.ts": 1593, + "scripts/tests/test-weights.test.ts": 1829, + "scripts/tests/tracked.test.ts": 1563, + "scripts/tests/verify-adapter.test.ts": 7638, + "scripts/tests/verify-clean.test.ts": 1756, + "scripts/tests/verify-coordinator.test.ts": 1932, + "scripts/tests/version-lockstep.test.ts": 1757, + "scripts/tests/web-client-module.test.ts": 1536, + "scripts/tests/workspace.test.ts": 1558 }, "node": { - "packages/acp/tests/acceptance.test.ts": 2214, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4877, - "packages/acp/tests/acpx-materialization.test.ts": 7085, + "packages/acp/tests/acceptance.test.ts": 2147, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4862, + "packages/acp/tests/acpx-materialization.test.ts": 7066, "packages/acp/tests/acpx-transient-env.test.ts": 831, - "packages/acp/tests/adapter-materialization.test.ts": 74897, - "packages/acp/tests/adapter-protocol.test.ts": 55440, - "packages/acp/tests/codex-surfaces.test.ts": 670, - "packages/acp/tests/native-launch.test.ts": 2283, - "packages/acp/tests/permission-bridge.test.ts": 1272, - "packages/acp/tests/provider.test.ts": 2223, - "packages/acp/tests/serial-queue.test.ts": 499, - "packages/acp/tests/session-key.test.ts": 551, + "packages/acp/tests/adapter-materialization.test.ts": 75480, + "packages/acp/tests/adapter-protocol.test.ts": 56405, + "packages/acp/tests/codex-surfaces.test.ts": 655, + "packages/acp/tests/native-launch.test.ts": 2201, + "packages/acp/tests/permission-bridge.test.ts": 1229, + "packages/acp/tests/provider.test.ts": 2181, + "packages/acp/tests/serial-queue.test.ts": 492, + "packages/acp/tests/session-key.test.ts": 531, "packages/acp/tests/terminal-screen.test.ts": 624, - "packages/cli/tests/agent-adapters.test.ts": 2528, - "packages/cli/tests/agent-cli.test.ts": 43989, - "packages/cli/tests/agent-config.test.ts": 487, - "packages/cli/tests/agent-options-cli.test.ts": 16335, - "packages/cli/tests/agent-options.test.ts": 494, - "packages/cli/tests/agent-session-coordinator.test.ts": 1365, - "packages/cli/tests/cli-help.test.ts": 40794, - "packages/cli/tests/command.test.ts": 14816, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 4258, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 172135, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 3627, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 9948, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 6186, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 18155, - "packages/cli/tests/evaluate-component.test.ts": 15406, - "packages/cli/tests/fetch-cli.test.ts": 4942, - "packages/cli/tests/file-stream.test.ts": 536, - "packages/cli/tests/inline-cli.test.ts": 67652, - "packages/cli/tests/launch-timeout.test.ts": 20546, - "packages/cli/tests/packaged-document.test.ts": 1594, - "packages/cli/tests/plan-args.test.ts": 507, - "packages/cli/tests/plan-cli.test.ts": 118889, - "packages/cli/tests/plan-command-document.test.ts": 8078, - "packages/cli/tests/plan-component.test.ts": 11071, - "packages/cli/tests/plan-host-acts.test.ts": 2359, - "packages/cli/tests/plan.test.ts": 15760, - "packages/cli/tests/plugin-cli.test.ts": 82043, - "packages/cli/tests/plugin-host.test.ts": 3277, - "packages/cli/tests/plugin-modules.test.ts": 487, - "packages/cli/tests/plugin-selection.test.ts": 514, - "packages/cli/tests/process-retention.test.ts": 4876, - "packages/cli/tests/props-cli.test.ts": 63573, - "packages/cli/tests/props-schema.test.ts": 1342, - "packages/cli/tests/props-sources.test.ts": 690, - "packages/cli/tests/repl-boundaries.test.ts": 2486, - "packages/cli/tests/repl-composition.test.ts": 725, - "packages/cli/tests/repl-execution.test.ts": 2896, - "packages/cli/tests/repl-journey.test.ts": 11109, - "packages/cli/tests/repl-model.test.ts": 2703, - "packages/cli/tests/repl-route.test.ts": 2270, - "packages/cli/tests/repl-terminal.test.ts": 1276, - "packages/cli/tests/run-composition.test.ts": 4115, - "packages/cli/tests/run-deadline.test.ts": 3685, - "packages/cli/tests/run-profile.test.ts": 1236, - "packages/cli/tests/run-timeouts.test.ts": 20388, - "packages/cli/tests/secret-detection-cli.test.ts": 37989, - "packages/cli/tests/service-document.test.ts": 2573, - "packages/cli/tests/service-host.test.ts": 2340, - "packages/cli/tests/session-launch-cli.test.ts": 11070, - "packages/cli/tests/stdin-cli.test.ts": 63409, - "packages/cli/tests/stdout-delivery.test.ts": 497, - "packages/cli/tests/syntax-cli.test.ts": 62826, - "packages/cli/tests/targets-cli.test.ts": 51186, - "packages/cli/tests/test-root-profile.test.ts": 7084, - "packages/cli/tests/test-target.test.ts": 74365, - "packages/cli/tests/testing-activation.test.ts": 1516, - "packages/cli/tests/testing-execution-host.test.ts": 93380, - "packages/cli/tests/upgrade-cli.test.ts": 47918, - "packages/cli/tests/upgrade-command-document.test.ts": 5587, - "packages/cli/tests/upgrade-output.test.ts": 1896, - "packages/cli/tests/value-root.test.ts": 31919, - "packages/cli/tests/verbose-component.test.ts": 1944, - "packages/cli/tests/workflow-declaration.test.ts": 1458, - "packages/cli/tests/workflow-host.test.ts": 10902, - "packages/code-review-agent/tests/doctor.test.ts": 489, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 515, - "packages/code-review-agent/tests/parse-diff.test.ts": 507, - "packages/code-review-agent/tests/parse-doctor.test.ts": 1157, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 477, - "packages/code-review-agent/tests/policy.test.ts": 494, - "packages/core/tests/agent-api.test.ts": 514, - "packages/core/tests/agent-components.test.ts": 2041, - "packages/core/tests/agent-function-components.test.ts": 4301, - "packages/core/tests/agent-session-launch.test.ts": 4590, - "packages/core/tests/agent-session-placement.test.ts": 517, - "packages/core/tests/agent-session-use.test.ts": 503, - "packages/core/tests/agent-stack.test.ts": 1569, - "packages/core/tests/answer-identity.test.ts": 513, - "packages/core/tests/answers-component.test.ts": 2342, - "packages/core/tests/answers-expansion-recursion.test.ts": 979, - "packages/core/tests/capture-errors.test.ts": 1261, - "packages/core/tests/capture-props.test.ts": 991, - "packages/core/tests/cli-journal.test.ts": 22526, - "packages/core/tests/code-block-component.test.ts": 3318, - "packages/core/tests/compiler-boundary.test.ts": 1179, - "packages/core/tests/component-api.test.ts": 559, - "packages/core/tests/component-registration.test.ts": 2126, - "packages/core/tests/component-returns.test.ts": 2950, - "packages/core/tests/component-schema-conformance.test.ts": 1126, - "packages/core/tests/config-api.test.ts": 1317, - "packages/core/tests/construct-error-observation.test.ts": 1432, - "packages/core/tests/contextual-cwd.test.ts": 2499, - "packages/core/tests/daemon-integration.test.ts": 1955, - "packages/core/tests/daemon.test.ts": 595, - "packages/core/tests/declared-markdown-component.test.ts": 3319, - "packages/core/tests/document-output-api.test.ts": 520, - "packages/core/tests/document-target-execution.test.ts": 4941, - "packages/core/tests/document-targets.test.ts": 1246, - "packages/core/tests/document-validation.test.ts": 3151, - "packages/core/tests/documentation-index.test.ts": 904, - "packages/core/tests/each.test.ts": 1348, - "packages/core/tests/elicit-component.test.ts": 2100, - "packages/core/tests/ephemeral-service.test.ts": 1907, - "packages/core/tests/eval-bindings.test.ts": 1306, - "packages/core/tests/eval-context.test.ts": 673, - "packages/core/tests/eval-durable.test.ts": 1382, - "packages/core/tests/eval-error-mode.test.ts": 1732, - "packages/core/tests/eval-interpolate.test.ts": 521, - "packages/core/tests/eval-middleware.test.ts": 604, - "packages/core/tests/eval-persist.test.ts": 1475, - "packages/core/tests/eval-return.test.ts": 1359, - "packages/core/tests/eval-scope.test.ts": 1173, - "packages/core/tests/eval-timeout.test.ts": 1347, - "packages/core/tests/eval-transform.test.ts": 590, - "packages/core/tests/evaluate-component.test.ts": 3762, - "packages/core/tests/evaluate-loaded-copy.test.ts": 1404, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 1467, - "packages/core/tests/evaluation-profile.test.ts": 898, - "packages/core/tests/exec-timeout.test.ts": 1413, - "packages/core/tests/execute.test.ts": 2063, - "packages/core/tests/execution-protocol.test.ts": 2931, - "packages/core/tests/expand.test.ts": 2017, - "packages/core/tests/expansion-identity.test.ts": 2065, - "packages/core/tests/expansion-metadata.test.ts": 1026, - "packages/core/tests/expression-props.test.ts": 1884, - "packages/core/tests/fail-component.test.ts": 1678, - "packages/core/tests/failure-printing.test.ts": 1484, - "packages/core/tests/fatal-cause.test.ts": 893, - "packages/core/tests/fetch-component.test.ts": 2938, - "packages/core/tests/file-component.test.ts": 3461, - "packages/core/tests/file-delete-component.test.ts": 1504, - "packages/core/tests/files-fatal.test.ts": 2437, - "packages/core/tests/foreground-exec.test.ts": 2319, - "packages/core/tests/frontmatter.test.ts": 553, - "packages/core/tests/function-components.test.ts": 2057, - "packages/core/tests/generated-composition.test.ts": 2059, - "packages/core/tests/generated-xmd.test.ts": 3590, - "packages/core/tests/glob-api.test.ts": 595, - "packages/core/tests/glob-component.test.ts": 2107, - "packages/core/tests/guarded-journal.test.ts": 1330, - "packages/core/tests/has-content.test.ts": 949, - "packages/core/tests/heal.test.ts": 945, - "packages/core/tests/if.test.ts": 1850, - "packages/core/tests/inline-root.test.ts": 1347, - "packages/core/tests/invocation-failures.test.ts": 590, - "packages/core/tests/invocation-identity.test.ts": 1686, - "packages/core/tests/invocation-scope.test.ts": 1215, - "packages/core/tests/journal-source-position.test.ts": 1456, - "packages/core/tests/json-component.test.ts": 1549, - "packages/core/tests/json.test.ts": 500, - "packages/core/tests/let.test.ts": 1354, - "packages/core/tests/loop.test.ts": 2322, - "packages/core/tests/named-slots.test.ts": 2291, - "packages/core/tests/output-error-mode.test.ts": 2574, - "packages/core/tests/output-normalize.test.ts": 523, - "packages/core/tests/output-terminal.test.ts": 678, - "packages/core/tests/parse-components.test.ts": 1418, - "packages/core/tests/plan-response.test.ts": 617, - "packages/core/tests/plugin-api.test.ts": 524, - "packages/core/tests/plugin.test.ts": 994, - "packages/core/tests/props-binding.test.ts": 1442, - "packages/core/tests/protected-content.test.ts": 550, - "packages/core/tests/registered-printed-errors.test.ts": 849, - "packages/core/tests/replay-stream.test.ts": 492, - "packages/core/tests/retain.test.ts": 1158, - "packages/core/tests/root-composition.test.ts": 1382, - "packages/core/tests/root-props.test.ts": 1478, - "packages/core/tests/root-provider.test.ts": 1360, - "packages/core/tests/sample-component.test.ts": 2419, - "packages/core/tests/scanner.test.ts": 602, - "packages/core/tests/scope-local.test.ts": 513, - "packages/core/tests/secret-detection.test.ts": 2190, - "packages/core/tests/secret-files.test.ts": 770, - "packages/core/tests/secret-rules.test.ts": 841, - "packages/core/tests/secret-scanner-baseline.test.ts": 790, - "packages/core/tests/secret-scanner.test.ts": 718, - "packages/core/tests/source-position.test.ts": 1169, - "packages/core/tests/state-ownership.test.ts": 1257, - "packages/core/tests/streaming-emission.test.ts": 1186, - "packages/core/tests/switch.test.ts": 1908, - "packages/core/tests/syntax-catalog.test.ts": 1912, - "packages/core/tests/syntax-component.test.ts": 2776, - "packages/core/tests/temp-dir.test.ts": 3772, - "packages/core/tests/temp-file-compiler.test.ts": 575, - "packages/core/tests/text-interpolation.test.ts": 947, - "packages/core/tests/try-content.test.ts": 957, - "packages/core/tests/unused-in-diff.test.ts": 1369, - "packages/core/tests/validate.test.ts": 807, - "packages/core/tests/validation-integration.test.ts": 1211, - "packages/core/tests/workflow-component-bundle.test.ts": 1592, - "packages/durable-streams/tests/context.test.ts": 529, - "packages/durable-streams/tests/deterministic-id.test.ts": 557, - "packages/durable-streams/tests/divergence-api.test.ts": 553, - "packages/durable-streams/tests/divergence.test.ts": 586, - "packages/durable-streams/tests/durable-each.test.ts": 591, - "packages/durable-streams/tests/durable-position.test.ts": 554, - "packages/durable-streams/tests/durable-run.test.ts": 564, - "packages/durable-streams/tests/ephemeral.test.ts": 550, - "packages/durable-streams/tests/fail-stop.test.ts": 617, - "packages/durable-streams/tests/guard-stream.test.ts": 630, - "packages/durable-streams/tests/live-coordinator.test.ts": 553, - "packages/durable-streams/tests/parse.test.ts": 582, - "packages/durable-streams/tests/replay-guard.test.ts": 587, - "packages/durable-streams/tests/replay-index.test.ts": 546, - "packages/durable-streams/tests/retained.test.ts": 530, - "packages/durable-streams/tests/serialize-event.test.ts": 546, - "packages/durable-streams/tests/smoke.test.ts": 540, - "packages/durable-streams/tests/structured-concurrency.test.ts": 611, - "packages/durable-streams/tests/terminal-boundary.test.ts": 577, - "packages/durable-streams/tests/types.test.ts": 522, - "packages/git/tests/api-entrypoint.test.ts": 1280, - "packages/git/tests/git-host-effect.test.ts": 7174, - "packages/git/tests/git.test.ts": 1304, - "packages/git/tests/github-activation.test.ts": 1694, - "packages/git/tests/github-issues.test.ts": 1218, - "packages/git/tests/github-pull-requests.test.ts": 605, - "packages/git/tests/issue-markdown.test.ts": 10086, - "packages/git/tests/issue-records.test.ts": 1178, - "packages/git/tests/module-partition.test.ts": 3239, - "packages/git/tests/plugin.test.ts": 1737, - "packages/git/tests/provider-neutrality.test.ts": 2298, - "packages/git/tests/pull-request-records.test.ts": 1273, - "packages/git/tests/run-composition-lazy.test.ts": 1993, - "packages/git/tests/selection-authentication.test.ts": 497, - "packages/runtime/tests/duration.test.ts": 476, - "packages/runtime/tests/fetch.test.ts": 1115, - "packages/runtime/tests/fs.test.ts": 569, - "packages/runtime/tests/host-files.test.ts": 1317, - "packages/runtime/tests/native-launcher.test.ts": 2885, - "packages/runtime/tests/process.test.ts": 542, - "packages/runtime/tests/service.test.ts": 555, - "packages/test-agent/tests/acp-server.test.ts": 684, - "packages/test-agent/tests/behavior-engine.test.ts": 1616, - "packages/test-agent/tests/bridge.test.ts": 527, - "packages/test-agent/tests/command-lazy.test.ts": 6698, - "packages/test-agent/tests/components.test.ts": 108320, - "packages/test-agent/tests/controller.test.ts": 807, - "packages/test-agent/tests/cross-package-resolution.test.ts": 2949, - "packages/test-agent/tests/native-launch.test.ts": 55467, - "packages/test-agent/tests/net.test.ts": 597, - "packages/test-agent/tests/profile.test.ts": 1185, - "packages/test-agent/tests/protocol.test.ts": 607, - "packages/test-agent/tests/provider.test.ts": 1400, - "packages/test-agent/tests/public-api.test.ts": 1576, - "packages/test-agent/tests/route-slot.test.ts": 510, - "packages/test-agent/tests/smoke.test.ts": 29490, - "packages/test-agent/tests/template.test.ts": 1181, - "packages/test-agent/tests/worker-lifecycle.test.ts": 24412, - "packages/test-support/tests/journal.test.ts": 516, - "packages/testing/tests/agent-composition.test.ts": 1550, - "packages/testing/tests/assert-throws.test.ts": 3272, - "packages/testing/tests/assert.test.ts": 546, - "packages/testing/tests/assertions.test.ts": 3984, - "packages/testing/tests/boundary-contract.test.ts": 2633, - "packages/testing/tests/cli.test.ts": 11610, - "packages/testing/tests/execution-harness.test.ts": 7778, - "packages/testing/tests/replay.test.ts": 3111, - "packages/testing/tests/smoke.test.ts": 3510, - "packages/testing/tests/test-component.test.ts": 4058, - "packages/testing/tests/testing-activation.test.ts": 3530, - "packages/testing/tests/testing-boundary.test.ts": 2114, - "packages/testing/tests/testing-mode.test.ts": 4196, - "packages/testing/tests/use-testing.test.ts": 2982, - "packages/web/tests/assets.test.ts": 505, - "packages/web/tests/client-logic.test.ts": 564, - "packages/web/tests/compile.test.ts": 2013, - "packages/web/tests/component.test.ts": 2622, - "packages/web/tests/declaration.test.ts": 1740, - "packages/web/tests/document.test.ts": 1828, - "packages/web/tests/elicitation.test.ts": 1633, - "packages/web/tests/live-form.test.ts": 1516, - "packages/web/tests/markdown.test.ts": 719, - "packages/web/tests/opener.test.ts": 1551, - "packages/web/tests/page.test.ts": 497, - "packages/web/tests/responder.test.ts": 1899, - "packages/web/tests/server-lifecycle.test.ts": 1696, - "packages/web/tests/server.test.ts": 2090, - "packages/workflow/tests/generated-observations.test.ts": 1528, - "packages/workflow/tests/retained-run.test.ts": 2350, - "packages/workflow/tests/service-denial.test.ts": 536, - "packages/workflow/tests/workflow-bundle.test.ts": 1645, - "packages/workflow/tests/workflow-definition.test.ts": 1368, - "packages/workflow/tests/workflow-fork.test.ts": 1228, - "packages/workflow/tests/workflow-run.test.ts": 2138, - "packages/workflow/tests/workspace-effect.test.ts": 3176, - "packages/workflow/tests/xmd-artifact.test.ts": 3981, - "scripts/tests/adapter-vendor.test.ts": 748, - "scripts/tests/bootstrap-npm-package.test.ts": 8714, - "scripts/tests/bump-version.test.ts": 640, - "scripts/tests/changed-paths.test.ts": 555, - "scripts/tests/ci-workflow.test.ts": 3812, - "scripts/tests/consumer-cycle.test.ts": 695, - "scripts/tests/filesystem-contract-workflow.test.ts": 598, - "scripts/tests/main-green.test.ts": 797, - "scripts/tests/main-health.test.ts": 626, - "scripts/tests/no-module-scoped-registry.test.ts": 1399, - "scripts/tests/no-redundant-test-scope.test.ts": 5451, - "scripts/tests/no-sync-filesystem.test.ts": 5830, - "scripts/tests/no-yield-in-finally.test.ts": 1331, - "scripts/tests/oxlint-policy.test.ts": 11385, - "scripts/tests/packaged-document.test.ts": 636, - "scripts/tests/prefer-effection-operation.test.ts": 6792, - "scripts/tests/prefer-effection-result.test.ts": 4734, - "scripts/tests/publish-workflow-membership.test.ts": 681, - "scripts/tests/review-infrastructure.test.ts": 3482, - "scripts/tests/runtime-exclusions.test.ts": 1041, - "scripts/tests/runtime-tests.test.ts": 585, - "scripts/tests/scope-bound-event-registration.test.ts": 5632, - "scripts/tests/staged-write.test.ts": 551, - "scripts/tests/test-file-discovery.test.ts": 877, - "scripts/tests/test-shards.test.ts": 570, - "scripts/tests/test-weights.test.ts": 762, - "scripts/tests/tracked.test.ts": 541, + "packages/cli/tests/agent-adapters.test.ts": 2472, + "packages/cli/tests/agent-cli.test.ts": 43764, + "packages/cli/tests/agent-config.test.ts": 500, + "packages/cli/tests/agent-options-cli.test.ts": 16751, + "packages/cli/tests/agent-options.test.ts": 522, + "packages/cli/tests/agent-session-coordinator.test.ts": 1411, + "packages/cli/tests/cli-help.test.ts": 41839, + "packages/cli/tests/command.test.ts": 15202, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 4371, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 172095, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 3658, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 10009, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 6132, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 18184, + "packages/cli/tests/evaluate-component.test.ts": 15576, + "packages/cli/tests/fetch-cli.test.ts": 5042, + "packages/cli/tests/file-stream.test.ts": 553, + "packages/cli/tests/inline-cli.test.ts": 69253, + "packages/cli/tests/launch-timeout.test.ts": 20556, + "packages/cli/tests/packaged-document.test.ts": 1703, + "packages/cli/tests/plan-args.test.ts": 530, + "packages/cli/tests/plan-cli.test.ts": 123356, + "packages/cli/tests/plan-command-document.test.ts": 8342, + "packages/cli/tests/plan-component.test.ts": 11574, + "packages/cli/tests/plan-host-acts.test.ts": 2493, + "packages/cli/tests/plan.test.ts": 16183, + "packages/cli/tests/plugin-cli.test.ts": 83902, + "packages/cli/tests/plugin-host.test.ts": 3312, + "packages/cli/tests/plugin-modules.test.ts": 503, + "packages/cli/tests/plugin-selection.test.ts": 501, + "packages/cli/tests/process-retention.test.ts": 4939, + "packages/cli/tests/props-cli.test.ts": 64277, + "packages/cli/tests/props-schema.test.ts": 1366, + "packages/cli/tests/props-sources.test.ts": 725, + "packages/cli/tests/repl-boundaries.test.ts": 2599, + "packages/cli/tests/repl-composition.test.ts": 757, + "packages/cli/tests/repl-execution.test.ts": 2984, + "packages/cli/tests/repl-journey.test.ts": 11219, + "packages/cli/tests/repl-model.test.ts": 2751, + "packages/cli/tests/repl-route.test.ts": 2323, + "packages/cli/tests/repl-terminal.test.ts": 1299, + "packages/cli/tests/run-composition.test.ts": 4155, + "packages/cli/tests/run-deadline.test.ts": 3703, + "packages/cli/tests/run-profile.test.ts": 1248, + "packages/cli/tests/run-timeouts.test.ts": 20443, + "packages/cli/tests/secret-detection-cli.test.ts": 38329, + "packages/cli/tests/service-document.test.ts": 2608, + "packages/cli/tests/service-host.test.ts": 2376, + "packages/cli/tests/session-launch-cli.test.ts": 11240, + "packages/cli/tests/stdin-cli.test.ts": 64256, + "packages/cli/tests/stdout-delivery.test.ts": 505, + "packages/cli/tests/syntax-cli.test.ts": 63780, + "packages/cli/tests/targets-cli.test.ts": 51410, + "packages/cli/tests/test-root-profile.test.ts": 7052, + "packages/cli/tests/test-target.test.ts": 73779, + "packages/cli/tests/testing-activation.test.ts": 1493, + "packages/cli/tests/testing-execution-host.test.ts": 91221, + "packages/cli/tests/upgrade-cli.test.ts": 46915, + "packages/cli/tests/upgrade-command-document.test.ts": 5542, + "packages/cli/tests/upgrade-output.test.ts": 1974, + "packages/cli/tests/value-root.test.ts": 32957, + "packages/cli/tests/verbose-component.test.ts": 1951, + "packages/cli/tests/workflow-declaration.test.ts": 1506, + "packages/cli/tests/workflow-host.test.ts": 11110, + "packages/code-review-agent/tests/doctor.test.ts": 510, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 528, + "packages/code-review-agent/tests/parse-diff.test.ts": 508, + "packages/code-review-agent/tests/parse-doctor.test.ts": 1178, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 491, + "packages/code-review-agent/tests/policy.test.ts": 502, + "packages/core/tests/agent-api.test.ts": 508, + "packages/core/tests/agent-components.test.ts": 2045, + "packages/core/tests/agent-function-components.test.ts": 4256, + "packages/core/tests/agent-session-launch.test.ts": 4597, + "packages/core/tests/agent-session-placement.test.ts": 508, + "packages/core/tests/agent-session-use.test.ts": 486, + "packages/core/tests/agent-stack.test.ts": 1520, + "packages/core/tests/all.test.ts": 2954, + "packages/core/tests/answer-identity.test.ts": 572, + "packages/core/tests/answers-component.test.ts": 2393, + "packages/core/tests/answers-expansion-recursion.test.ts": 969, + "packages/core/tests/capture-errors.test.ts": 1255, + "packages/core/tests/capture-props.test.ts": 1006, + "packages/core/tests/cli-journal.test.ts": 22366, + "packages/core/tests/code-block-component.test.ts": 3204, + "packages/core/tests/compiler-boundary.test.ts": 1148, + "packages/core/tests/component-api.test.ts": 540, + "packages/core/tests/component-registration.test.ts": 2102, + "packages/core/tests/component-returns.test.ts": 2887, + "packages/core/tests/component-schema-conformance.test.ts": 1154, + "packages/core/tests/config-api.test.ts": 1278, + "packages/core/tests/construct-error-observation.test.ts": 1400, + "packages/core/tests/contextual-cwd.test.ts": 2451, + "packages/core/tests/daemon-integration.test.ts": 1919, + "packages/core/tests/daemon.test.ts": 576, + "packages/core/tests/declared-markdown-component.test.ts": 3179, + "packages/core/tests/document-output-api.test.ts": 512, + "packages/core/tests/document-target-execution.test.ts": 4694, + "packages/core/tests/document-targets.test.ts": 1195, + "packages/core/tests/document-validation.test.ts": 3029, + "packages/core/tests/documentation-index.test.ts": 839, + "packages/core/tests/each.test.ts": 1269, + "packages/core/tests/elicit-component.test.ts": 2044, + "packages/core/tests/ephemeral-service.test.ts": 1842, + "packages/core/tests/eval-bindings.test.ts": 1279, + "packages/core/tests/eval-context.test.ts": 599, + "packages/core/tests/eval-durable.test.ts": 1328, + "packages/core/tests/eval-error-mode.test.ts": 1658, + "packages/core/tests/eval-interpolate.test.ts": 507, + "packages/core/tests/eval-middleware.test.ts": 598, + "packages/core/tests/eval-persist.test.ts": 1380, + "packages/core/tests/eval-return.test.ts": 1277, + "packages/core/tests/eval-scope.test.ts": 1206, + "packages/core/tests/eval-timeout.test.ts": 1268, + "packages/core/tests/eval-transform.test.ts": 588, + "packages/core/tests/evaluate-component.test.ts": 3665, + "packages/core/tests/evaluate-loaded-copy.test.ts": 1380, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 1419, + "packages/core/tests/evaluation-profile.test.ts": 887, + "packages/core/tests/exec-timeout.test.ts": 1342, + "packages/core/tests/execute.test.ts": 1998, + "packages/core/tests/execution-protocol.test.ts": 2813, + "packages/core/tests/expand.test.ts": 1980, + "packages/core/tests/expansion-identity.test.ts": 2012, + "packages/core/tests/expansion-metadata.test.ts": 1020, + "packages/core/tests/expression-props.test.ts": 1880, + "packages/core/tests/fail-component.test.ts": 1667, + "packages/core/tests/failure-printing.test.ts": 1463, + "packages/core/tests/fatal-cause.test.ts": 876, + "packages/core/tests/fetch-component.test.ts": 2924, + "packages/core/tests/file-component.test.ts": 3417, + "packages/core/tests/file-delete-component.test.ts": 1494, + "packages/core/tests/files-fatal.test.ts": 2511, + "packages/core/tests/foreground-exec.test.ts": 2337, + "packages/core/tests/frontmatter.test.ts": 558, + "packages/core/tests/function-components.test.ts": 1988, + "packages/core/tests/generated-composition.test.ts": 2075, + "packages/core/tests/generated-xmd.test.ts": 3603, + "packages/core/tests/glob-api.test.ts": 593, + "packages/core/tests/glob-component.test.ts": 2069, + "packages/core/tests/guarded-journal.test.ts": 1356, + "packages/core/tests/has-content.test.ts": 931, + "packages/core/tests/heal.test.ts": 941, + "packages/core/tests/if.test.ts": 1832, + "packages/core/tests/inline-root.test.ts": 1366, + "packages/core/tests/invocation-failures.test.ts": 600, + "packages/core/tests/invocation-identity.test.ts": 1791, + "packages/core/tests/invocation-scope.test.ts": 1201, + "packages/core/tests/journal-source-position.test.ts": 1451, + "packages/core/tests/json-component.test.ts": 1587, + "packages/core/tests/json.test.ts": 497, + "packages/core/tests/let.test.ts": 1332, + "packages/core/tests/loop.test.ts": 2313, + "packages/core/tests/named-slots.test.ts": 2317, + "packages/core/tests/output-error-mode.test.ts": 2657, + "packages/core/tests/output-normalize.test.ts": 507, + "packages/core/tests/output-terminal.test.ts": 694, + "packages/core/tests/parse-components.test.ts": 1454, + "packages/core/tests/plan-response.test.ts": 594, + "packages/core/tests/plugin-api.test.ts": 529, + "packages/core/tests/plugin.test.ts": 1006, + "packages/core/tests/props-binding.test.ts": 1467, + "packages/core/tests/protected-content.test.ts": 558, + "packages/core/tests/registered-printed-errors.test.ts": 863, + "packages/core/tests/replay-stream.test.ts": 506, + "packages/core/tests/retain.test.ts": 1137, + "packages/core/tests/root-composition.test.ts": 1407, + "packages/core/tests/root-props.test.ts": 1480, + "packages/core/tests/root-provider.test.ts": 1350, + "packages/core/tests/sample-component.test.ts": 2358, + "packages/core/tests/scanner.test.ts": 578, + "packages/core/tests/scope-local.test.ts": 505, + "packages/core/tests/secret-detection.test.ts": 2130, + "packages/core/tests/secret-files.test.ts": 774, + "packages/core/tests/secret-rules.test.ts": 860, + "packages/core/tests/secret-scanner-baseline.test.ts": 755, + "packages/core/tests/secret-scanner.test.ts": 702, + "packages/core/tests/source-position.test.ts": 1166, + "packages/core/tests/state-ownership.test.ts": 1254, + "packages/core/tests/streaming-emission.test.ts": 1175, + "packages/core/tests/switch.test.ts": 1881, + "packages/core/tests/syntax-catalog.test.ts": 1843, + "packages/core/tests/syntax-component.test.ts": 2691, + "packages/core/tests/temp-dir.test.ts": 3741, + "packages/core/tests/temp-file-compiler.test.ts": 551, + "packages/core/tests/text-interpolation.test.ts": 912, + "packages/core/tests/try-content.test.ts": 939, + "packages/core/tests/unused-in-diff.test.ts": 1354, + "packages/core/tests/validate.test.ts": 818, + "packages/core/tests/validation-integration.test.ts": 1192, + "packages/core/tests/workflow-component-bundle.test.ts": 1577, + "packages/durable-streams/tests/context.test.ts": 516, + "packages/durable-streams/tests/deterministic-id.test.ts": 544, + "packages/durable-streams/tests/divergence-api.test.ts": 537, + "packages/durable-streams/tests/divergence.test.ts": 576, + "packages/durable-streams/tests/durable-each.test.ts": 578, + "packages/durable-streams/tests/durable-position.test.ts": 549, + "packages/durable-streams/tests/durable-run.test.ts": 555, + "packages/durable-streams/tests/ephemeral.test.ts": 559, + "packages/durable-streams/tests/fail-stop.test.ts": 636, + "packages/durable-streams/tests/guard-stream.test.ts": 628, + "packages/durable-streams/tests/live-coordinator.test.ts": 543, + "packages/durable-streams/tests/parse.test.ts": 573, + "packages/durable-streams/tests/replay-guard.test.ts": 605, + "packages/durable-streams/tests/replay-index.test.ts": 543, + "packages/durable-streams/tests/retained.test.ts": 515, + "packages/durable-streams/tests/serialize-event.test.ts": 545, + "packages/durable-streams/tests/smoke.test.ts": 521, + "packages/durable-streams/tests/structured-concurrency.test.ts": 621, + "packages/durable-streams/tests/terminal-boundary.test.ts": 574, + "packages/durable-streams/tests/types.test.ts": 491, + "packages/git/tests/api-entrypoint.test.ts": 1319, + "packages/git/tests/git-host-effect.test.ts": 7549, + "packages/git/tests/git.test.ts": 1318, + "packages/git/tests/github-activation.test.ts": 1688, + "packages/git/tests/github-issues.test.ts": 1216, + "packages/git/tests/github-pull-requests.test.ts": 604, + "packages/git/tests/issue-markdown.test.ts": 10038, + "packages/git/tests/issue-records.test.ts": 1202, + "packages/git/tests/module-partition.test.ts": 3280, + "packages/git/tests/plugin.test.ts": 1723, + "packages/git/tests/provider-neutrality.test.ts": 2318, + "packages/git/tests/pull-request-records.test.ts": 1248, + "packages/git/tests/run-composition-lazy.test.ts": 2035, + "packages/git/tests/selection-authentication.test.ts": 489, + "packages/runtime/tests/duration.test.ts": 486, + "packages/runtime/tests/fetch.test.ts": 1123, + "packages/runtime/tests/fs.test.ts": 555, + "packages/runtime/tests/host-files.test.ts": 1291, + "packages/runtime/tests/native-launcher.test.ts": 2851, + "packages/runtime/tests/process.test.ts": 548, + "packages/runtime/tests/service.test.ts": 523, + "packages/test-agent/tests/acp-server.test.ts": 667, + "packages/test-agent/tests/behavior-engine.test.ts": 1586, + "packages/test-agent/tests/bridge.test.ts": 528, + "packages/test-agent/tests/command-lazy.test.ts": 6610, + "packages/test-agent/tests/components.test.ts": 107656, + "packages/test-agent/tests/controller.test.ts": 824, + "packages/test-agent/tests/cross-package-resolution.test.ts": 3031, + "packages/test-agent/tests/native-launch.test.ts": 55277, + "packages/test-agent/tests/net.test.ts": 602, + "packages/test-agent/tests/profile.test.ts": 1191, + "packages/test-agent/tests/protocol.test.ts": 614, + "packages/test-agent/tests/provider.test.ts": 1373, + "packages/test-agent/tests/public-api.test.ts": 1532, + "packages/test-agent/tests/route-slot.test.ts": 521, + "packages/test-agent/tests/smoke.test.ts": 29089, + "packages/test-agent/tests/template.test.ts": 1187, + "packages/test-agent/tests/worker-lifecycle.test.ts": 24095, + "packages/test-support/tests/journal.test.ts": 526, + "packages/testing/tests/agent-composition.test.ts": 1538, + "packages/testing/tests/assert-throws.test.ts": 3371, + "packages/testing/tests/assert.test.ts": 527, + "packages/testing/tests/assertions.test.ts": 3893, + "packages/testing/tests/boundary-contract.test.ts": 2577, + "packages/testing/tests/cli.test.ts": 11249, + "packages/testing/tests/execution-harness.test.ts": 7889, + "packages/testing/tests/replay.test.ts": 3161, + "packages/testing/tests/smoke.test.ts": 3257, + "packages/testing/tests/test-component.test.ts": 3874, + "packages/testing/tests/testing-activation.test.ts": 3441, + "packages/testing/tests/testing-boundary.test.ts": 2024, + "packages/testing/tests/testing-mode.test.ts": 4100, + "packages/testing/tests/use-testing.test.ts": 2929, + "packages/web/tests/assets.test.ts": 502, + "packages/web/tests/client-logic.test.ts": 545, + "packages/web/tests/compile.test.ts": 2042, + "packages/web/tests/component.test.ts": 2621, + "packages/web/tests/declaration.test.ts": 1760, + "packages/web/tests/document.test.ts": 1859, + "packages/web/tests/elicitation.test.ts": 1631, + "packages/web/tests/live-form.test.ts": 1546, + "packages/web/tests/markdown.test.ts": 721, + "packages/web/tests/opener.test.ts": 1558, + "packages/web/tests/page.test.ts": 504, + "packages/web/tests/responder.test.ts": 1867, + "packages/web/tests/server-lifecycle.test.ts": 1673, + "packages/web/tests/server.test.ts": 2131, + "packages/workflow/tests/generated-observations.test.ts": 1601, + "packages/workflow/tests/retained-run.test.ts": 2288, + "packages/workflow/tests/service-denial.test.ts": 542, + "packages/workflow/tests/workflow-bundle.test.ts": 1707, + "packages/workflow/tests/workflow-definition.test.ts": 1386, + "packages/workflow/tests/workflow-fork.test.ts": 1225, + "packages/workflow/tests/workflow-run.test.ts": 2209, + "packages/workflow/tests/workspace-effect.test.ts": 3116, + "packages/workflow/tests/xmd-artifact.test.ts": 3692, + "scripts/tests/adapter-vendor.test.ts": 744, + "scripts/tests/bootstrap-npm-package.test.ts": 8423, + "scripts/tests/bump-version.test.ts": 619, + "scripts/tests/changed-paths.test.ts": 526, + "scripts/tests/ci-workflow.test.ts": 3623, + "scripts/tests/consumer-cycle.test.ts": 683, + "scripts/tests/filesystem-contract-workflow.test.ts": 593, + "scripts/tests/main-green.test.ts": 779, + "scripts/tests/main-health.test.ts": 622, + "scripts/tests/no-module-scoped-registry.test.ts": 1340, + "scripts/tests/no-redundant-test-scope.test.ts": 5431, + "scripts/tests/no-sync-filesystem.test.ts": 5783, + "scripts/tests/no-yield-in-finally.test.ts": 1341, + "scripts/tests/oxlint-policy.test.ts": 11094, + "scripts/tests/packaged-document.test.ts": 601, + "scripts/tests/prefer-effection-operation.test.ts": 6511, + "scripts/tests/prefer-effection-result.test.ts": 4678, + "scripts/tests/publish-workflow-membership.test.ts": 692, + "scripts/tests/review-infrastructure.test.ts": 3415, + "scripts/tests/runtime-exclusions.test.ts": 1095, + "scripts/tests/runtime-tests.test.ts": 589, + "scripts/tests/scope-bound-event-registration.test.ts": 5516, + "scripts/tests/staged-write.test.ts": 585, + "scripts/tests/test-file-discovery.test.ts": 866, + "scripts/tests/test-shards.test.ts": 559, + "scripts/tests/test-weights.test.ts": 749, + "scripts/tests/tracked.test.ts": 534, "scripts/tests/verify-coordinator.test.ts": 769, - "scripts/tests/version-lockstep.test.ts": 739, - "scripts/tests/web-client-module.test.ts": 541, - "scripts/tests/workspace.test.ts": 522 + "scripts/tests/version-lockstep.test.ts": 719, + "scripts/tests/web-client-module.test.ts": 536, + "scripts/tests/workspace.test.ts": 505 }, "bun": { - "packages/acp/tests/acceptance.test.ts": 848, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4324, - "packages/acp/tests/acpx-materialization.test.ts": 6530, - "packages/acp/tests/acpx-transient-env.test.ts": 278, - "packages/acp/tests/adapter-materialization.test.ts": 72466, - "packages/acp/tests/adapter-protocol.test.ts": 54696, - "packages/acp/tests/codex-surfaces.test.ts": 128, - "packages/acp/tests/native-launch.test.ts": 1014, - "packages/acp/tests/permission-bridge.test.ts": 376, - "packages/acp/tests/provider.test.ts": 1144, - "packages/acp/tests/serial-queue.test.ts": 113, - "packages/acp/tests/session-key.test.ts": 66, - "packages/acp/tests/terminal-screen.test.ts": 92, - "packages/cli/tests/agent-adapters.test.ts": 1259, - "packages/cli/tests/agent-cli.test.ts": 21242, - "packages/cli/tests/agent-config.test.ts": 31, - "packages/cli/tests/agent-options-cli.test.ts": 8066, + "packages/acp/tests/acceptance.test.ts": 890, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4354, + "packages/acp/tests/acpx-materialization.test.ts": 6513, + "packages/acp/tests/acpx-transient-env.test.ts": 253, + "packages/acp/tests/adapter-materialization.test.ts": 71896, + "packages/acp/tests/adapter-protocol.test.ts": 54722, + "packages/acp/tests/codex-surfaces.test.ts": 124, + "packages/acp/tests/native-launch.test.ts": 997, + "packages/acp/tests/permission-bridge.test.ts": 359, + "packages/acp/tests/provider.test.ts": 1112, + "packages/acp/tests/serial-queue.test.ts": 69, + "packages/acp/tests/session-key.test.ts": 69, + "packages/acp/tests/terminal-screen.test.ts": 97, + "packages/cli/tests/agent-adapters.test.ts": 1196, + "packages/cli/tests/agent-cli.test.ts": 20602, + "packages/cli/tests/agent-config.test.ts": 30, + "packages/cli/tests/agent-options-cli.test.ts": 7840, "packages/cli/tests/agent-options.test.ts": 34, - "packages/cli/tests/agent-session-coordinator.test.ts": 395, - "packages/cli/tests/cli-help.test.ts": 16491, - "packages/cli/tests/command.test.ts": 8086, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 3158, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 108257, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 2354, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 5383, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 4959, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 9210, - "packages/cli/tests/evaluate-component.test.ts": 8317, - "packages/cli/tests/fetch-cli.test.ts": 2541, - "packages/cli/tests/file-stream.test.ts": 60, - "packages/cli/tests/inline-cli.test.ts": 34088, - "packages/cli/tests/launch-timeout.test.ts": 10106, - "packages/cli/tests/packaged-document.test.ts": 496, - "packages/cli/tests/plan-args.test.ts": 40, - "packages/cli/tests/plan-cli.test.ts": 60861, - "packages/cli/tests/plan-command-document.test.ts": 5509, - "packages/cli/tests/plan-component.test.ts": 9021, - "packages/cli/tests/plan-host-acts.test.ts": 1232, - "packages/cli/tests/plan.test.ts": 12888, - "packages/cli/tests/plugin-cli.test.ts": 40868, - "packages/cli/tests/plugin-host.test.ts": 2176, + "packages/cli/tests/agent-session-coordinator.test.ts": 443, + "packages/cli/tests/cli-help.test.ts": 16040, + "packages/cli/tests/command.test.ts": 7978, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 3100, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 106189, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 2340, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 5163, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 4831, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 8968, + "packages/cli/tests/evaluate-component.test.ts": 7888, + "packages/cli/tests/fetch-cli.test.ts": 2329, + "packages/cli/tests/file-stream.test.ts": 56, + "packages/cli/tests/inline-cli.test.ts": 32163, + "packages/cli/tests/launch-timeout.test.ts": 10092, + "packages/cli/tests/packaged-document.test.ts": 471, + "packages/cli/tests/plan-args.test.ts": 37, + "packages/cli/tests/plan-cli.test.ts": 58708, + "packages/cli/tests/plan-command-document.test.ts": 5339, + "packages/cli/tests/plan-component.test.ts": 8740, + "packages/cli/tests/plan-host-acts.test.ts": 1166, + "packages/cli/tests/plan.test.ts": 13069, + "packages/cli/tests/plugin-cli.test.ts": 39698, + "packages/cli/tests/plugin-host.test.ts": 2058, "packages/cli/tests/plugin-modules.test.ts": 39, "packages/cli/tests/plugin-selection.test.ts": 38, - "packages/cli/tests/process-retention.test.ts": 2572, - "packages/cli/tests/props-cli.test.ts": 29734, - "packages/cli/tests/props-schema.test.ts": 441, - "packages/cli/tests/props-sources.test.ts": 145, - "packages/cli/tests/repl-boundaries.test.ts": 1250, - "packages/cli/tests/repl-composition.test.ts": 148, - "packages/cli/tests/repl-execution.test.ts": 2066, - "packages/cli/tests/repl-journey.test.ts": 10452, - "packages/cli/tests/repl-model.test.ts": 1788, - "packages/cli/tests/repl-route.test.ts": 1362, - "packages/cli/tests/repl-terminal.test.ts": 870, - "packages/cli/tests/run-composition.test.ts": 3267, - "packages/cli/tests/run-deadline.test.ts": 2464, - "packages/cli/tests/run-profile.test.ts": 329, - "packages/cli/tests/run-timeouts.test.ts": 11631, - "packages/cli/tests/secret-detection-cli.test.ts": 18885, - "packages/cli/tests/service-document.test.ts": 1561, - "packages/cli/tests/service-host.test.ts": 1429, - "packages/cli/tests/session-launch-cli.test.ts": 5781, - "packages/cli/tests/stdin-cli.test.ts": 32151, - "packages/cli/tests/stdout-delivery.test.ts": 53, - "packages/cli/tests/syntax-cli.test.ts": 34163, - "packages/cli/tests/targets-cli.test.ts": 22514, - "packages/cli/tests/test-root-profile.test.ts": 3779, - "packages/cli/tests/test-target.test.ts": 38358, - "packages/cli/tests/testing-activation.test.ts": 623, - "packages/cli/tests/testing-execution-host.test.ts": 51169, - "packages/cli/tests/upgrade-cli.test.ts": 19117, - "packages/cli/tests/upgrade-command-document.test.ts": 3715, - "packages/cli/tests/upgrade-output.test.ts": 849, - "packages/cli/tests/value-root.test.ts": 16527, - "packages/cli/tests/verbose-component.test.ts": 871, - "packages/cli/tests/workflow-declaration.test.ts": 586, - "packages/cli/tests/workflow-host.test.ts": 4412, - "packages/code-review-agent/tests/doctor.test.ts": 30, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 44, - "packages/code-review-agent/tests/parse-diff.test.ts": 40, - "packages/code-review-agent/tests/parse-doctor.test.ts": 305, + "packages/cli/tests/process-retention.test.ts": 2449, + "packages/cli/tests/props-cli.test.ts": 28963, + "packages/cli/tests/props-schema.test.ts": 432, + "packages/cli/tests/props-sources.test.ts": 125, + "packages/cli/tests/repl-boundaries.test.ts": 1294, + "packages/cli/tests/repl-composition.test.ts": 147, + "packages/cli/tests/repl-execution.test.ts": 1941, + "packages/cli/tests/repl-journey.test.ts": 10292, + "packages/cli/tests/repl-model.test.ts": 1718, + "packages/cli/tests/repl-route.test.ts": 1238, + "packages/cli/tests/repl-terminal.test.ts": 840, + "packages/cli/tests/run-composition.test.ts": 3125, + "packages/cli/tests/run-deadline.test.ts": 2377, + "packages/cli/tests/run-profile.test.ts": 312, + "packages/cli/tests/run-timeouts.test.ts": 11379, + "packages/cli/tests/secret-detection-cli.test.ts": 18442, + "packages/cli/tests/service-document.test.ts": 1524, + "packages/cli/tests/service-host.test.ts": 1402, + "packages/cli/tests/session-launch-cli.test.ts": 5637, + "packages/cli/tests/stdin-cli.test.ts": 31362, + "packages/cli/tests/stdout-delivery.test.ts": 54, + "packages/cli/tests/syntax-cli.test.ts": 33389, + "packages/cli/tests/targets-cli.test.ts": 22183, + "packages/cli/tests/test-root-profile.test.ts": 3765, + "packages/cli/tests/test-target.test.ts": 36487, + "packages/cli/tests/testing-activation.test.ts": 581, + "packages/cli/tests/testing-execution-host.test.ts": 49745, + "packages/cli/tests/upgrade-cli.test.ts": 18478, + "packages/cli/tests/upgrade-command-document.test.ts": 3538, + "packages/cli/tests/upgrade-output.test.ts": 830, + "packages/cli/tests/value-root.test.ts": 16272, + "packages/cli/tests/verbose-component.test.ts": 818, + "packages/cli/tests/workflow-declaration.test.ts": 551, + "packages/cli/tests/workflow-host.test.ts": 4237, + "packages/code-review-agent/tests/doctor.test.ts": 29, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 41, + "packages/code-review-agent/tests/parse-diff.test.ts": 36, + "packages/code-review-agent/tests/parse-doctor.test.ts": 296, "packages/code-review-agent/tests/parse-oxlint.test.ts": 31, - "packages/code-review-agent/tests/policy.test.ts": 32, - "packages/core/tests/agent-api.test.ts": 39, - "packages/core/tests/agent-components.test.ts": 1350, - "packages/core/tests/agent-function-components.test.ts": 3753, - "packages/core/tests/agent-session-launch.test.ts": 3650, - "packages/core/tests/agent-session-placement.test.ts": 38, - "packages/core/tests/agent-session-use.test.ts": 32, - "packages/core/tests/agent-stack.test.ts": 739, - "packages/core/tests/answer-identity.test.ts": 44, - "packages/core/tests/answers-component.test.ts": 1492, - "packages/core/tests/answers-expansion-recursion.test.ts": 342, - "packages/core/tests/capture-errors.test.ts": 622, - "packages/core/tests/capture-props.test.ts": 353, - "packages/core/tests/cli-journal.test.ts": 10935, - "packages/core/tests/code-block-component.test.ts": 2418, - "packages/core/tests/compiler-boundary.test.ts": 350, - "packages/core/tests/component-api.test.ts": 57, - "packages/core/tests/component-registration.test.ts": 1189, - "packages/core/tests/component-returns.test.ts": 1729, - "packages/core/tests/component-schema-conformance.test.ts": 588, - "packages/core/tests/config-api.test.ts": 353, - "packages/core/tests/construct-error-observation.test.ts": 755, - "packages/core/tests/contextual-cwd.test.ts": 1556, - "packages/core/tests/daemon-integration.test.ts": 1057, - "packages/core/tests/daemon.test.ts": 72, - "packages/core/tests/declared-markdown-component.test.ts": 2229, - "packages/core/tests/document-output-api.test.ts": 39, - "packages/core/tests/document-target-execution.test.ts": 3709, - "packages/core/tests/document-targets.test.ts": 460, - "packages/core/tests/document-validation.test.ts": 2283, - "packages/core/tests/documentation-index.test.ts": 168, - "packages/core/tests/each.test.ts": 444, - "packages/core/tests/elicit-component.test.ts": 1213, - "packages/core/tests/ephemeral-service.test.ts": 862, - "packages/core/tests/eval-bindings.test.ts": 438, - "packages/core/tests/eval-context.test.ts": 94, - "packages/core/tests/eval-durable.test.ts": 456, - "packages/core/tests/eval-error-mode.test.ts": 722, - "packages/core/tests/eval-interpolate.test.ts": 38, - "packages/core/tests/eval-middleware.test.ts": 87, - "packages/core/tests/eval-persist.test.ts": 525, - "packages/core/tests/eval-return.test.ts": 446, - "packages/core/tests/eval-scope.test.ts": 354, - "packages/core/tests/eval-timeout.test.ts": 461, - "packages/core/tests/eval-transform.test.ts": 67, - "packages/core/tests/evaluate-component.test.ts": 2725, - "packages/core/tests/evaluate-loaded-copy.test.ts": 543, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 677, - "packages/core/tests/evaluation-profile.test.ts": 197, - "packages/core/tests/exec-timeout.test.ts": 522, - "packages/core/tests/execute.test.ts": 1101, - "packages/core/tests/execution-protocol.test.ts": 1668, - "packages/core/tests/expand.test.ts": 1284, - "packages/core/tests/expansion-identity.test.ts": 1262, - "packages/core/tests/expansion-metadata.test.ts": 354, - "packages/core/tests/expression-props.test.ts": 904, - "packages/core/tests/fail-component.test.ts": 778, - "packages/core/tests/failure-printing.test.ts": 712, - "packages/core/tests/fatal-cause.test.ts": 195, - "packages/core/tests/fetch-component.test.ts": 1808, - "packages/core/tests/file-component.test.ts": 2448, - "packages/core/tests/file-delete-component.test.ts": 655, - "packages/core/tests/files-fatal.test.ts": 1553, - "packages/core/tests/foreground-exec.test.ts": 1280, - "packages/core/tests/frontmatter.test.ts": 48, - "packages/core/tests/function-components.test.ts": 953, - "packages/core/tests/generated-composition.test.ts": 1238, - "packages/core/tests/generated-xmd.test.ts": 2487, - "packages/core/tests/glob-api.test.ts": 102, - "packages/core/tests/glob-component.test.ts": 1268, - "packages/core/tests/guarded-journal.test.ts": 456, - "packages/core/tests/has-content.test.ts": 283, - "packages/core/tests/heal.test.ts": 267, - "packages/core/tests/if.test.ts": 859, - "packages/core/tests/inline-root.test.ts": 525, + "packages/code-review-agent/tests/policy.test.ts": 35, + "packages/core/tests/agent-api.test.ts": 40, + "packages/core/tests/agent-components.test.ts": 1263, + "packages/core/tests/agent-function-components.test.ts": 3627, + "packages/core/tests/agent-session-launch.test.ts": 3441, + "packages/core/tests/agent-session-placement.test.ts": 37, + "packages/core/tests/agent-session-use.test.ts": 34, + "packages/core/tests/agent-stack.test.ts": 767, + "packages/core/tests/all.test.ts": 2117, + "packages/core/tests/answer-identity.test.ts": 62, + "packages/core/tests/answers-component.test.ts": 1395, + "packages/core/tests/answers-expansion-recursion.test.ts": 326, + "packages/core/tests/capture-errors.test.ts": 617, + "packages/core/tests/capture-props.test.ts": 337, + "packages/core/tests/cli-journal.test.ts": 10770, + "packages/core/tests/code-block-component.test.ts": 2652, + "packages/core/tests/compiler-boundary.test.ts": 349, + "packages/core/tests/component-api.test.ts": 54, + "packages/core/tests/component-registration.test.ts": 1268, + "packages/core/tests/component-returns.test.ts": 1728, + "packages/core/tests/component-schema-conformance.test.ts": 576, + "packages/core/tests/config-api.test.ts": 357, + "packages/core/tests/construct-error-observation.test.ts": 787, + "packages/core/tests/contextual-cwd.test.ts": 1558, + "packages/core/tests/daemon-integration.test.ts": 1063, + "packages/core/tests/daemon.test.ts": 77, + "packages/core/tests/declared-markdown-component.test.ts": 2195, + "packages/core/tests/document-output-api.test.ts": 40, + "packages/core/tests/document-target-execution.test.ts": 3846, + "packages/core/tests/document-targets.test.ts": 446, + "packages/core/tests/document-validation.test.ts": 2234, + "packages/core/tests/documentation-index.test.ts": 172, + "packages/core/tests/each.test.ts": 435, + "packages/core/tests/elicit-component.test.ts": 1156, + "packages/core/tests/ephemeral-service.test.ts": 883, + "packages/core/tests/eval-bindings.test.ts": 422, + "packages/core/tests/eval-context.test.ts": 88, + "packages/core/tests/eval-durable.test.ts": 463, + "packages/core/tests/eval-error-mode.test.ts": 701, + "packages/core/tests/eval-interpolate.test.ts": 39, + "packages/core/tests/eval-middleware.test.ts": 78, + "packages/core/tests/eval-persist.test.ts": 520, + "packages/core/tests/eval-return.test.ts": 452, + "packages/core/tests/eval-scope.test.ts": 352, + "packages/core/tests/eval-timeout.test.ts": 462, + "packages/core/tests/eval-transform.test.ts": 65, + "packages/core/tests/evaluate-component.test.ts": 2630, + "packages/core/tests/evaluate-loaded-copy.test.ts": 535, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 660, + "packages/core/tests/evaluation-profile.test.ts": 205, + "packages/core/tests/exec-timeout.test.ts": 526, + "packages/core/tests/execute.test.ts": 1048, + "packages/core/tests/execution-protocol.test.ts": 1714, + "packages/core/tests/expand.test.ts": 1380, + "packages/core/tests/expansion-identity.test.ts": 1315, + "packages/core/tests/expansion-metadata.test.ts": 364, + "packages/core/tests/expression-props.test.ts": 958, + "packages/core/tests/fail-component.test.ts": 805, + "packages/core/tests/failure-printing.test.ts": 713, + "packages/core/tests/fatal-cause.test.ts": 200, + "packages/core/tests/fetch-component.test.ts": 1878, + "packages/core/tests/file-component.test.ts": 2550, + "packages/core/tests/file-delete-component.test.ts": 643, + "packages/core/tests/files-fatal.test.ts": 1613, + "packages/core/tests/foreground-exec.test.ts": 1329, + "packages/core/tests/frontmatter.test.ts": 52, + "packages/core/tests/function-components.test.ts": 972, + "packages/core/tests/generated-composition.test.ts": 1221, + "packages/core/tests/generated-xmd.test.ts": 2533, + "packages/core/tests/glob-api.test.ts": 101, + "packages/core/tests/glob-component.test.ts": 1289, + "packages/core/tests/guarded-journal.test.ts": 484, + "packages/core/tests/has-content.test.ts": 280, + "packages/core/tests/heal.test.ts": 273, + "packages/core/tests/if.test.ts": 872, + "packages/core/tests/inline-root.test.ts": 514, "packages/core/tests/invocation-failures.test.ts": 107, - "packages/core/tests/invocation-identity.test.ts": 833, - "packages/core/tests/invocation-scope.test.ts": 551, - "packages/core/tests/journal-source-position.test.ts": 564, - "packages/core/tests/json-component.test.ts": 2397, - "packages/core/tests/json.test.ts": 34, - "packages/core/tests/let.test.ts": 431, - "packages/core/tests/loop.test.ts": 1360, - "packages/core/tests/named-slots.test.ts": 1386, - "packages/core/tests/output-error-mode.test.ts": 1660, - "packages/core/tests/output-normalize.test.ts": 42, - "packages/core/tests/output-terminal.test.ts": 161, - "packages/core/tests/parse-components.test.ts": 607, + "packages/core/tests/invocation-identity.test.ts": 923, + "packages/core/tests/invocation-scope.test.ts": 573, + "packages/core/tests/journal-source-position.test.ts": 597, + "packages/core/tests/json-component.test.ts": 2468, + "packages/core/tests/json.test.ts": 35, + "packages/core/tests/let.test.ts": 437, + "packages/core/tests/loop.test.ts": 1331, + "packages/core/tests/named-slots.test.ts": 1353, + "packages/core/tests/output-error-mode.test.ts": 1664, + "packages/core/tests/output-normalize.test.ts": 44, + "packages/core/tests/output-terminal.test.ts": 165, + "packages/core/tests/parse-components.test.ts": 660, "packages/core/tests/plan-response.test.ts": 88, "packages/core/tests/plugin-api.test.ts": 49, - "packages/core/tests/plugin.test.ts": 192, - "packages/core/tests/props-binding.test.ts": 552, - "packages/core/tests/protected-content.test.ts": 55, - "packages/core/tests/registered-printed-errors.test.ts": 212, - "packages/core/tests/replay-stream.test.ts": 39, - "packages/core/tests/retain.test.ts": 482, - "packages/core/tests/root-composition.test.ts": 587, - "packages/core/tests/root-props.test.ts": 594, - "packages/core/tests/root-provider.test.ts": 682, - "packages/core/tests/sample-component.test.ts": 1135, - "packages/core/tests/scanner.test.ts": 79, - "packages/core/tests/scope-local.test.ts": 37, - "packages/core/tests/secret-detection.test.ts": 1155, - "packages/core/tests/secret-files.test.ts": 135, - "packages/core/tests/secret-rules.test.ts": 155, - "packages/core/tests/secret-scanner-baseline.test.ts": 148, - "packages/core/tests/secret-scanner.test.ts": 101, - "packages/core/tests/source-position.test.ts": 348, - "packages/core/tests/state-ownership.test.ts": 407, - "packages/core/tests/streaming-emission.test.ts": 326, - "packages/core/tests/switch.test.ts": 853, - "packages/core/tests/syntax-catalog.test.ts": 903, - "packages/core/tests/syntax-component.test.ts": 1824, - "packages/core/tests/temp-dir.test.ts": 2847, - "packages/core/tests/temp-file-compiler.test.ts": 81, - "packages/core/tests/text-interpolation.test.ts": 245, - "packages/core/tests/try-content.test.ts": 283, - "packages/core/tests/unused-in-diff.test.ts": 501, - "packages/core/tests/validate.test.ts": 332, - "packages/core/tests/validation-integration.test.ts": 378, - "packages/core/tests/workflow-component-bundle.test.ts": 736, - "packages/durable-streams/tests/context.test.ts": 40, - "packages/durable-streams/tests/deterministic-id.test.ts": 72, - "packages/durable-streams/tests/divergence-api.test.ts": 47, - "packages/durable-streams/tests/divergence.test.ts": 57, - "packages/durable-streams/tests/durable-each.test.ts": 71, - "packages/durable-streams/tests/durable-position.test.ts": 59, - "packages/durable-streams/tests/durable-run.test.ts": 65, - "packages/durable-streams/tests/ephemeral.test.ts": 63, - "packages/durable-streams/tests/fail-stop.test.ts": 80, - "packages/durable-streams/tests/guard-stream.test.ts": 108, - "packages/durable-streams/tests/live-coordinator.test.ts": 59, - "packages/durable-streams/tests/parse.test.ts": 50, + "packages/core/tests/plugin.test.ts": 200, + "packages/core/tests/props-binding.test.ts": 567, + "packages/core/tests/protected-content.test.ts": 53, + "packages/core/tests/registered-printed-errors.test.ts": 223, + "packages/core/tests/replay-stream.test.ts": 38, + "packages/core/tests/retain.test.ts": 500, + "packages/core/tests/root-composition.test.ts": 596, + "packages/core/tests/root-props.test.ts": 630, + "packages/core/tests/root-provider.test.ts": 662, + "packages/core/tests/sample-component.test.ts": 1260, + "packages/core/tests/scanner.test.ts": 82, + "packages/core/tests/scope-local.test.ts": 38, + "packages/core/tests/secret-detection.test.ts": 1204, + "packages/core/tests/secret-files.test.ts": 130, + "packages/core/tests/secret-rules.test.ts": 164, + "packages/core/tests/secret-scanner-baseline.test.ts": 156, + "packages/core/tests/secret-scanner.test.ts": 103, + "packages/core/tests/source-position.test.ts": 364, + "packages/core/tests/state-ownership.test.ts": 421, + "packages/core/tests/streaming-emission.test.ts": 335, + "packages/core/tests/switch.test.ts": 884, + "packages/core/tests/syntax-catalog.test.ts": 962, + "packages/core/tests/syntax-component.test.ts": 1905, + "packages/core/tests/temp-dir.test.ts": 2876, + "packages/core/tests/temp-file-compiler.test.ts": 85, + "packages/core/tests/text-interpolation.test.ts": 242, + "packages/core/tests/try-content.test.ts": 281, + "packages/core/tests/unused-in-diff.test.ts": 529, + "packages/core/tests/validate.test.ts": 346, + "packages/core/tests/validation-integration.test.ts": 383, + "packages/core/tests/workflow-component-bundle.test.ts": 780, + "packages/durable-streams/tests/context.test.ts": 38, + "packages/durable-streams/tests/deterministic-id.test.ts": 78, + "packages/durable-streams/tests/divergence-api.test.ts": 49, + "packages/durable-streams/tests/divergence.test.ts": 61, + "packages/durable-streams/tests/durable-each.test.ts": 74, + "packages/durable-streams/tests/durable-position.test.ts": 58, + "packages/durable-streams/tests/durable-run.test.ts": 68, + "packages/durable-streams/tests/ephemeral.test.ts": 65, + "packages/durable-streams/tests/fail-stop.test.ts": 77, + "packages/durable-streams/tests/guard-stream.test.ts": 103, + "packages/durable-streams/tests/live-coordinator.test.ts": 62, + "packages/durable-streams/tests/parse.test.ts": 52, "packages/durable-streams/tests/replay-guard.test.ts": 75, "packages/durable-streams/tests/replay-index.test.ts": 46, - "packages/durable-streams/tests/retained.test.ts": 103, - "packages/durable-streams/tests/serialize-event.test.ts": 52, - "packages/durable-streams/tests/smoke.test.ts": 34, - "packages/durable-streams/tests/structured-concurrency.test.ts": 97, - "packages/durable-streams/tests/terminal-boundary.test.ts": 82, - "packages/durable-streams/tests/types.test.ts": 29, - "packages/git/tests/api-entrypoint.test.ts": 311, - "packages/git/tests/git-host-effect.test.ts": 6642, - "packages/git/tests/git.test.ts": 375, - "packages/git/tests/github-activation.test.ts": 745, - "packages/git/tests/github-issues.test.ts": 326, - "packages/git/tests/github-pull-requests.test.ts": 83, - "packages/git/tests/issue-markdown.test.ts": 8625, - "packages/git/tests/issue-records.test.ts": 314, - "packages/git/tests/module-partition.test.ts": 1952, - "packages/git/tests/plugin.test.ts": 855, - "packages/git/tests/provider-neutrality.test.ts": 1105, - "packages/git/tests/pull-request-records.test.ts": 335, - "packages/git/tests/run-composition-lazy.test.ts": 827, - "packages/git/tests/selection-authentication.test.ts": 39, - "packages/runtime/tests/duration.test.ts": 30, - "packages/runtime/tests/fetch.test.ts": 613, - "packages/runtime/tests/fs.test.ts": 78, - "packages/runtime/tests/host-files.test.ts": 737, - "packages/runtime/tests/native-launcher.test.ts": 2414, - "packages/runtime/tests/process.test.ts": 89, - "packages/runtime/tests/service.test.ts": 67, - "packages/test-agent/tests/acp-server.test.ts": 109, - "packages/test-agent/tests/behavior-engine.test.ts": 695, - "packages/test-agent/tests/bridge.test.ts": 68, - "packages/test-agent/tests/command-lazy.test.ts": 3360, - "packages/test-agent/tests/components.test.ts": 53390, - "packages/test-agent/tests/controller.test.ts": 210, - "packages/test-agent/tests/cross-package-resolution.test.ts": 1966, - "packages/test-agent/tests/native-launch.test.ts": 24823, - "packages/test-agent/tests/net.test.ts": 109, - "packages/test-agent/tests/profile.test.ts": 305, - "packages/test-agent/tests/protocol.test.ts": 60, - "packages/test-agent/tests/provider.test.ts": 442, - "packages/test-agent/tests/public-api.test.ts": 483, - "packages/test-agent/tests/route-slot.test.ts": 59, - "packages/test-agent/tests/smoke.test.ts": 15697, - "packages/test-agent/tests/template.test.ts": 303, - "packages/test-agent/tests/worker-lifecycle.test.ts": 9536, - "packages/test-support/tests/journal.test.ts": 43, - "packages/testing/tests/agent-composition.test.ts": 629, - "packages/testing/tests/assert-throws.test.ts": 2381, + "packages/durable-streams/tests/retained.test.ts": 45, + "packages/durable-streams/tests/serialize-event.test.ts": 43, + "packages/durable-streams/tests/smoke.test.ts": 49, + "packages/durable-streams/tests/structured-concurrency.test.ts": 148, + "packages/durable-streams/tests/terminal-boundary.test.ts": 79, + "packages/durable-streams/tests/types.test.ts": 30, + "packages/git/tests/api-entrypoint.test.ts": 330, + "packages/git/tests/git-host-effect.test.ts": 6986, + "packages/git/tests/git.test.ts": 405, + "packages/git/tests/github-activation.test.ts": 765, + "packages/git/tests/github-issues.test.ts": 337, + "packages/git/tests/github-pull-requests.test.ts": 86, + "packages/git/tests/issue-markdown.test.ts": 9264, + "packages/git/tests/issue-records.test.ts": 311, + "packages/git/tests/module-partition.test.ts": 1988, + "packages/git/tests/plugin.test.ts": 846, + "packages/git/tests/provider-neutrality.test.ts": 1117, + "packages/git/tests/pull-request-records.test.ts": 339, + "packages/git/tests/run-composition-lazy.test.ts": 843, + "packages/git/tests/selection-authentication.test.ts": 40, + "packages/runtime/tests/duration.test.ts": 31, + "packages/runtime/tests/fetch.test.ts": 623, + "packages/runtime/tests/fs.test.ts": 70, + "packages/runtime/tests/host-files.test.ts": 735, + "packages/runtime/tests/native-launcher.test.ts": 2428, + "packages/runtime/tests/process.test.ts": 96, + "packages/runtime/tests/service.test.ts": 64, + "packages/test-agent/tests/acp-server.test.ts": 113, + "packages/test-agent/tests/behavior-engine.test.ts": 713, + "packages/test-agent/tests/bridge.test.ts": 71, + "packages/test-agent/tests/command-lazy.test.ts": 3362, + "packages/test-agent/tests/components.test.ts": 54248, + "packages/test-agent/tests/controller.test.ts": 217, + "packages/test-agent/tests/cross-package-resolution.test.ts": 1962, + "packages/test-agent/tests/native-launch.test.ts": 25442, + "packages/test-agent/tests/net.test.ts": 105, + "packages/test-agent/tests/profile.test.ts": 320, + "packages/test-agent/tests/protocol.test.ts": 63, + "packages/test-agent/tests/provider.test.ts": 429, + "packages/test-agent/tests/public-api.test.ts": 504, + "packages/test-agent/tests/route-slot.test.ts": 60, + "packages/test-agent/tests/smoke.test.ts": 16103, + "packages/test-agent/tests/template.test.ts": 312, + "packages/test-agent/tests/worker-lifecycle.test.ts": 9757, + "packages/test-support/tests/journal.test.ts": 44, + "packages/testing/tests/agent-composition.test.ts": 673, + "packages/testing/tests/assert-throws.test.ts": 2560, "packages/testing/tests/assert.test.ts": 58, - "packages/testing/tests/assertions.test.ts": 3069, - "packages/testing/tests/boundary-contract.test.ts": 1670, - "packages/testing/tests/cli.test.ts": 5153, - "packages/testing/tests/execution-harness.test.ts": 6520, - "packages/testing/tests/replay.test.ts": 2317, - "packages/testing/tests/smoke.test.ts": 1858, - "packages/testing/tests/test-component.test.ts": 3031, - "packages/testing/tests/testing-activation.test.ts": 2654, - "packages/testing/tests/testing-boundary.test.ts": 1131, - "packages/testing/tests/testing-mode.test.ts": 3241, - "packages/testing/tests/use-testing.test.ts": 1882, - "packages/web/tests/assets.test.ts": 33, - "packages/web/tests/client-logic.test.ts": 38, - "packages/web/tests/compile.test.ts": 900, - "packages/web/tests/component.test.ts": 1465, - "packages/web/tests/declaration.test.ts": 687, - "packages/web/tests/document.test.ts": 794, - "packages/web/tests/elicitation.test.ts": 560, - "packages/web/tests/live-form.test.ts": 508, - "packages/web/tests/markdown.test.ts": 135, - "packages/web/tests/opener.test.ts": 505, - "packages/web/tests/page.test.ts": 34, - "packages/web/tests/responder.test.ts": 862, - "packages/web/tests/server-lifecycle.test.ts": 658, - "packages/web/tests/server.test.ts": 1077, - "packages/workflow/tests/generated-observations.test.ts": 540, - "packages/workflow/tests/retained-run.test.ts": 1212, - "packages/workflow/tests/service-denial.test.ts": 64, - "packages/workflow/tests/workflow-bundle.test.ts": 730, - "packages/workflow/tests/workflow-definition.test.ts": 359, - "packages/workflow/tests/workflow-fork.test.ts": 312, - "packages/workflow/tests/workflow-run.test.ts": 1068, - "packages/workflow/tests/workspace-effect.test.ts": 1523, - "scripts/tests/adapter-vendor.test.ts": 162, - "scripts/tests/bootstrap-npm-package.test.ts": 5570, - "scripts/tests/bump-version.test.ts": 88, - "scripts/tests/changed-paths.test.ts": 40, - "scripts/tests/ci-workflow.test.ts": 1939, - "scripts/tests/consumer-cycle.test.ts": 108, - "scripts/tests/filesystem-contract-workflow.test.ts": 76, - "scripts/tests/main-green.test.ts": 297, - "scripts/tests/main-health.test.ts": 104, - "scripts/tests/no-module-scoped-registry.test.ts": 891, - "scripts/tests/no-redundant-test-scope.test.ts": 4993, - "scripts/tests/no-sync-filesystem.test.ts": 4628, - "scripts/tests/no-yield-in-finally.test.ts": 883, - "scripts/tests/oxlint-policy.test.ts": 10564, - "scripts/tests/packaged-document.test.ts": 74, - "scripts/tests/prefer-effection-operation.test.ts": 6080, - "scripts/tests/prefer-effection-result.test.ts": 4219, - "scripts/tests/publish-workflow-membership.test.ts": 100, - "scripts/tests/review-infrastructure.test.ts": 1963, - "scripts/tests/runtime-exclusions.test.ts": 348, - "scripts/tests/runtime-tests.test.ts": 88, - "scripts/tests/scope-bound-event-registration.test.ts": 4633, - "scripts/tests/staged-write.test.ts": 71, - "scripts/tests/test-file-discovery.test.ts": 254, - "scripts/tests/test-shards.test.ts": 46, - "scripts/tests/test-weights.test.ts": 207, - "scripts/tests/tracked.test.ts": 38, - "scripts/tests/verify-coordinator.test.ts": 230, - "scripts/tests/version-lockstep.test.ts": 124, - "scripts/tests/web-client-module.test.ts": 63, - "scripts/tests/workspace.test.ts": 48 + "packages/testing/tests/assertions.test.ts": 3361, + "packages/testing/tests/boundary-contract.test.ts": 1777, + "packages/testing/tests/cli.test.ts": 5285, + "packages/testing/tests/execution-harness.test.ts": 7412, + "packages/testing/tests/replay.test.ts": 2320, + "packages/testing/tests/smoke.test.ts": 1999, + "packages/testing/tests/test-component.test.ts": 3228, + "packages/testing/tests/testing-activation.test.ts": 2839, + "packages/testing/tests/testing-boundary.test.ts": 1196, + "packages/testing/tests/testing-mode.test.ts": 3302, + "packages/testing/tests/use-testing.test.ts": 1960, + "packages/web/tests/assets.test.ts": 32, + "packages/web/tests/client-logic.test.ts": 39, + "packages/web/tests/compile.test.ts": 966, + "packages/web/tests/component.test.ts": 1541, + "packages/web/tests/declaration.test.ts": 737, + "packages/web/tests/document.test.ts": 798, + "packages/web/tests/elicitation.test.ts": 568, + "packages/web/tests/live-form.test.ts": 527, + "packages/web/tests/markdown.test.ts": 146, + "packages/web/tests/opener.test.ts": 496, + "packages/web/tests/page.test.ts": 35, + "packages/web/tests/responder.test.ts": 895, + "packages/web/tests/server-lifecycle.test.ts": 661, + "packages/web/tests/server.test.ts": 1089, + "packages/workflow/tests/generated-observations.test.ts": 633, + "packages/workflow/tests/retained-run.test.ts": 1392, + "packages/workflow/tests/service-denial.test.ts": 72, + "packages/workflow/tests/workflow-bundle.test.ts": 793, + "packages/workflow/tests/workflow-definition.test.ts": 377, + "packages/workflow/tests/workflow-fork.test.ts": 320, + "packages/workflow/tests/workflow-run.test.ts": 1193, + "packages/workflow/tests/workspace-effect.test.ts": 1588, + "scripts/tests/adapter-vendor.test.ts": 165, + "scripts/tests/bootstrap-npm-package.test.ts": 6390, + "scripts/tests/bump-version.test.ts": 99, + "scripts/tests/changed-paths.test.ts": 44, + "scripts/tests/ci-workflow.test.ts": 2072, + "scripts/tests/consumer-cycle.test.ts": 117, + "scripts/tests/filesystem-contract-workflow.test.ts": 81, + "scripts/tests/main-green.test.ts": 304, + "scripts/tests/main-health.test.ts": 108, + "scripts/tests/no-module-scoped-registry.test.ts": 936, + "scripts/tests/no-redundant-test-scope.test.ts": 5136, + "scripts/tests/no-sync-filesystem.test.ts": 4757, + "scripts/tests/no-yield-in-finally.test.ts": 921, + "scripts/tests/oxlint-policy.test.ts": 10843, + "scripts/tests/packaged-document.test.ts": 86, + "scripts/tests/prefer-effection-operation.test.ts": 6274, + "scripts/tests/prefer-effection-result.test.ts": 4291, + "scripts/tests/publish-workflow-membership.test.ts": 108, + "scripts/tests/review-infrastructure.test.ts": 2038, + "scripts/tests/runtime-exclusions.test.ts": 344, + "scripts/tests/runtime-tests.test.ts": 80, + "scripts/tests/scope-bound-event-registration.test.ts": 4757, + "scripts/tests/staged-write.test.ts": 75, + "scripts/tests/test-file-discovery.test.ts": 267, + "scripts/tests/test-shards.test.ts": 47, + "scripts/tests/test-weights.test.ts": 216, + "scripts/tests/tracked.test.ts": 40, + "scripts/tests/verify-coordinator.test.ts": 228, + "scripts/tests/version-lockstep.test.ts": 127, + "scripts/tests/web-client-module.test.ts": 61, + "scripts/tests/workspace.test.ts": 51 } } } From 3074395ea333d3f6c807edd6859b55672525022b Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Mon, 28 Sep 2026 18:26:40 -0400 Subject: [PATCH 03/12] =?UTF-8?q?=F0=9F=90=9B=20Sort=20the=20arrays=20`map?= =?UTF-8?q?`=20just=20made=20so=20the=20Node=20typecheck=20accepts=20them?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `toSorted()` is ES2023 and the Node typecheck targets ES2022, so two rows of the `` suite failed every `test-node` shard while Deno and Bun passed. `sort()` on the array `map` just made is the convention this repository already documents in `scripts/lib/verify.ts` and Git's remote-composition proof. --- packages/core/tests/all.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/core/tests/all.test.ts b/packages/core/tests/all.test.ts index 5016255bf..a1388c6a4 100644 --- a/packages/core/tests/all.test.ts +++ b/packages/core/tests/all.test.ts @@ -583,7 +583,10 @@ describe("Tier ALL — PA3: counters, paths and the parent's own numbering", () expect(onParent.map((entry) => entry.name)).toEqual(["eval:eval:root:0", "eval:eval:root:1"]); const inChildren = entries.filter((entry) => entry.coroutineId !== "root"); - expect(inChildren.map((entry) => entry.coroutineId).toSorted()).toEqual(["root.0", "root.1"]); + // `sort()` rather than `toSorted()`: the Node typecheck targets ES2022, where + // the latter does not exist, and the array being sorted is the one `map` just + // made — so there is nothing of anyone else's to mutate. + expect(inChildren.map((entry) => entry.coroutineId).sort()).toEqual(["root.0", "root.1"]); // Both children number their own first block the same way and collide with // nothing, because the child coroutine namespaces it. expect(new Set(inChildren.map((entry) => entry.name))).toEqual(new Set(["eval:eval:root:0"])); @@ -605,8 +608,9 @@ describe("Tier ALL — PA3: counters, paths and the parent's own numbering", () // which child appends first is exactly what scheduling is allowed to // decide — the contract fixes what a block is called and where, never the // order two independent children reach the journal. + // `sort()` for the same reason, on the array `map` just made. const identify = (found: EvalEntry[]): string[] => - found.map((entry) => `${entry.coroutineId}/${entry.name}`).toSorted(); + found.map((entry) => `${entry.coroutineId}/${entry.name}`).sort(); expect(identify(evalEntries(rerun.events))).toEqual(identify(entries)); // And a replay reproduces the rendering without running any of it. From 245457ecfa5f0e2affa5d452f08fb44d1a3e930f Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Mon, 28 Sep 2026 18:54:56 -0400 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=90=9B=20Let=20one=20definition=20a?= =?UTF-8?q?nswer=20more=20than=20one=20import,=20and=20report=20a=20mispla?= =?UTF-8?q?ced=20spawn=20once?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three corrections to the reviewed `` delivery. A claim was keyed by the answer object alone, which made the first resolution part of that object's permanent identity. A provider that owns one immutable definition and hands it to every import it answers was refused the second time — punished for not copying itself. The key is now the pair of answer and resolution window: what an object *is* stays settled by its first claim, so it cannot be renamed, re-originated or taken by another installation, while which import it answered is recorded per window. Each window keeps its own retained copy, so `identify()` still answers only for the window that claimed, and a second *different* answer in a window already spent still refuses. Reuse is of the definition, not merely of the reference. The first claim retains core's copy as the baseline the stated identity describes, and a later window may answer with that object only while it still describes it — so a provider cannot claim a definition, edit it, and have the next import record the edited one under the revision that described the original. An answer core could never retain does not become claimable because it changed. A `` written below an `` but not directly inside it was reported twice during non-executing validation: once by the ``'s own structure walk, which anchors the diagnostic at the misplaced element, and again by the element's own rule, whose guard only knew its immediate parent. The element's rule now owns exactly one case — a `` with no `` above it at all — and the walk owns every other. And the vocabulary: work owned by a `` is a spawn, a spawned child, sibling spawns, spawned concurrency. It was described as branching, which is what an `` arm and a `` are. Established meanings elsewhere are untouched. --- architecture.md | 11 +- packages/core/src/component-answers.ts | 4 +- .../src/components/component-resolution.ts | 153 +++++++--- packages/core/src/document-validation.ts | 24 +- packages/core/src/expand.ts | 2 +- packages/core/src/invocation-identity.ts | 21 +- packages/core/tests/all.test.ts | 35 ++- packages/core/tests/answer-identity.test.ts | 267 ++++++++++++++++-- .../core/tests/invocation-identity.test.ts | 16 +- specs/executable-mdx-spec.md | 13 +- 10 files changed, 445 insertions(+), 101 deletions(-) diff --git a/architecture.md b/architecture.md index abb42ecc6..0e4fbb719 100644 --- a/architecture.md +++ b/architecture.md @@ -4018,9 +4018,9 @@ recorded into the top frame of the scope that is resolving: - nesting inside one scope is unchanged — an inner import owns the top until it closes, and the outer one may be selected into again afterwards; -- sibling branches have independent tops, so one child's selection can never - land in another's frame, and closing or cancelling one branch neither clears - nor authorizes the other; +- sibling spawns have independent tops, so one spawned child's selection can + never land in another's frame, and closing or cancelling one spawn neither + clears nor authorizes the other; - a frame is removed only by the settle that opened it, from the scope that opened it, and teardown discards every remaining stack; and - two selections in *one* frame — a handler delegating twice — still yield no @@ -4031,8 +4031,9 @@ never reaches a document, a component, a provider or a handler: two frames belong together because they were opened under the same engine scope, not because of anything either of them says. The same ownership governs the canonical answer windows a provider claims through, where one installation may -hold an answer open in two branches at once and a second, different answer in -either still refuses. +hold an answer open in two sibling spawns at once — the exact same definition +included, because a reusable provider owns one object and a claim is per +window — and a second, *different* answer in either still refuses. The engine then mints one issuance per invocation, carrying that domain — or none — the authored name for what a refusal says, and the frame the body is diff --git a/packages/core/src/component-answers.ts b/packages/core/src/component-answers.ts index abaf1acf4..fa283dc2c 100644 --- a/packages/core/src/component-answers.ts +++ b/packages/core/src/component-answers.ts @@ -115,9 +115,9 @@ export function componentAnswerRegistrar( *around(handler: ComponentAnswerHandler): Operation { yield* Component.around({ *importComponent([name, position], next) { - // The scope this invocation is running in, which is the branch whose + // The scope this invocation is running in, which is the spawn whose // resolution this request answers. Read here rather than carried on - // the installation: one installation serves every branch, and two of + // the installation: one installation serves every spawn, and two of // them may be resolving at the same time. const asked = installation.open(yield* useScope(), name, position); try { diff --git a/packages/core/src/components/component-resolution.ts b/packages/core/src/components/component-resolution.ts index 361267d42..646e777a5 100644 --- a/packages/core/src/components/component-resolution.ts +++ b/packages/core/src/components/component-resolution.ts @@ -201,25 +201,54 @@ export interface IdentifiedAnswer { readonly definition: ImportedDefinition; } -/** One claim this owner recorded, with core's own copy of what was claimed. */ +/** + * What one answer object was claimed to be, and which resolutions claimed it. + * + * One implementation says what it is once, so the name, the identity and the + * installation belong to the object: a new resolution cannot rename it, restate + * its origin or revision, or take it for another provider. + * + * Which import it answered is a different question, and the answer to it is per + * resolution — so the copies are keyed by the window *object*, not by a number + * describing one. A caller asking about provenance presents the window it is + * holding, so the comparison is between two references to one thing rather than + * between a record and whatever the owner's mutable current state happens to + * say. A number would have to be trusted against that mutable state; an object + * cannot be forged into being the one the caller opened. + * + * A reusable provider returns one immutable definition to every import it + * answers. Keying the claim by the object alone made the first resolution part + * of the object's permanent identity and refused the same definition the second + * time, which is a provider being punished for not copying itself. + */ interface Claim { readonly name: string; readonly identity: AnswerIdentity; /** Which provider installation stated it, so a second cannot overwrite. */ readonly installation: object; /** - * The exact resolution this was an answer to. + * Core's copy of the definition the first claim described. + * + * The identity above is a statement about *this* definition, so a later claim + * of the same object has to be a claim about the same definition. Without this + * baseline, a provider could claim an object, edit it, and have the next window + * retain the edited version under the identity and revision that described the + * original — a different implementation wearing the first one's name. * - * The window *object*, not a number describing one. Provenance is a question - * about which import a statement answered, and a caller asking it presents - * the window it is holding — so the comparison is between two references to - * one thing rather than between a record and whatever the owner's mutable - * current state happens to say. A number would have to be trusted against - * that mutable state; an object cannot be forged into being the one the - * caller opened. + * Absent when the first claim could not be copied at all, which is not a state + * a later claim can improve: an answer core could not retain is not one it can + * start vouching for because the object has since changed. */ - readonly window: ResolutionWindow; - readonly canonical: ImportedDefinition | undefined; + readonly baseline: ImportedDefinition | undefined; + /** + * One retained copy per resolution this answer was claimed in. + * + * Weak on the window, so a claim lasts exactly as long as somebody still holds + * the resolution it belongs to. Presence is the provenance check: a window + * that never claimed this answer has no entry, and `identify` answers nothing + * for it however many other windows did. + */ + readonly copies: WeakMap; } /** A provider request used after its execution ended. */ @@ -358,11 +387,11 @@ export class CanonicalImports { * handler settled for one name from recording under it while a different * name is being resolved. * - * A stack per scope rather than one for the execution, because independent - * branches resolve at the same time. Nesting inside one scope stays LIFO — - * an inner resolution hides its parent until it closes — while a sibling - * branch has its own top, so closing or cancelling one can neither clear nor - * authorize the other. The scope object is a private key: never published, + * A stack per scope rather than one for the execution, because sibling spawns + * resolve at the same time. Nesting inside one scope stays LIFO — an inner + * resolution hides its parent until it closes — while each spawn has its own + * top, so closing or cancelling one can neither clear nor authorize the + * other. The scope object is a private key: never published, * never read from, and never handed to a provider. */ readonly #windows = new Map(); @@ -396,7 +425,7 @@ export class CanonicalImports { /** Stop. Called at teardown, on completion, failure or cancellation. */ revoke(): void { this.#active = false; - // Every scope's stack, not only the ones that emptied themselves: a branch + // Every scope's stack, not only the ones that emptied themselves: a spawn // torn down with a resolution still open leaves nothing claimable. this.#windows.clear(); } @@ -426,7 +455,7 @@ export class CanonicalImports { occurrence, close(): void { // Only this window, and only out of the scope that opened it. A nested - // resolution above it has its own close, and a sibling branch's stack + // resolution above it has its own close, and a sibling spawn's stack // is not touched at all — clearing either would settle a decision still // being made somewhere else. Removed by identity, so no bookkeeping // value has to be trusted to say which window this is, and idempotent, @@ -476,7 +505,7 @@ export class CanonicalImports { // of the scope that is resolving. A request minted while resolution N // is open answers resolution N or nothing: it holds the object, so it // cannot be made to describe whichever window is open later — or a - // window a different branch opened in the meantime. + // window a sibling spawn opened in the meantime. const opened = owner.#windows.get(scope)?.at(-1); let live = true; const request: ComponentAnswerRequest = Object.freeze({ @@ -538,14 +567,13 @@ export class CanonicalImports { const held = typeof answer === "object" && answer !== null ? this.#claims.get(answer) : undefined; if (held !== undefined) { - // Restating exactly what is already there is what a provider installed - // twice does, and it is not a conflict. Anything else is two providers - // disagreeing about one object, and the first statement stands: a later - // claim that overwrote it would let a second provider rename the first's - // implementation. + // What this object is was settled by its first claim. Restating it is what + // a provider installed twice does, and what a reusable one does for every + // import it answers; anything else is two providers disagreeing about one + // object, and the first statement stands — a later claim that overwrote it + // would let a second provider rename the first's implementation. if ( held.installation !== installation || - held.window !== open || held.name !== asked.name || held.identity.origin !== identity.origin || held.identity.key !== identity.key || @@ -556,6 +584,31 @@ export class CanonicalImports { "implementation states what it is once.", ); } + if (held.copies.has(open)) { + // Already recorded for this exact resolution, so there is nothing to + // add: one import is one implementation, and this is that one again. + return answer; + } + // Still the definition the identity was stated about. A claimed object the + // provider went on to edit is a different implementation, and taking a + // fresh copy of it here would record the edited one under the revision + // that described the original. Asked before anything is recorded and + // before the window is spent, so a refusal leaves both untouched. + if (held.baseline === undefined || !stillDescribes(held.baseline, answer)) { + throw new AnswerIdentityError( + "this answer no longer describes the implementation its identity was stated about, so a " + + "further import cannot be answered with it. One implementation states what it is " + + "once, and stays that.", + ); + } + // The same definition answering a different import. That is one provider + // reused, not a second answer — but it still spends *this* resolution, so + // a different answer afterwards refuses as it always did. + if (this.#spent.get(installation)?.has(open) === true) { + throw new AnswerIdentityError(SPENT_OPPORTUNITY); + } + held.copies.set(open, retain(answer)); + this.#spend(installation, open); return answer; } // Secondary, and about the provider rather than the invocation: naming a @@ -566,24 +619,35 @@ export class CanonicalImports { } // Copied on the way in, so a later edit of the claimed object is visible as // the change it is. + const baseline = retain(answer); + const copies = new WeakMap(); + copies.set(open, baseline); this.#claims.set(answer, { name: asked.name, identity, installation, - window: open, - canonical: retain(answer), + baseline, + copies, }); - // Spent for this window and no other: another import is a different window, - // which is what lets one installation answer several admitted names, the - // same name resolved twice, and two branches resolving at the same time — - // while a second answer in a window it already spent still refuses. + this.#spend(installation, open); + return answer; + } + + /** + * Record that this installation has answered this resolution. + * + * Spent for this window and no other: another import is a different window, + * which is what lets one installation answer several admitted names, the same + * name resolved twice, and sibling spawns resolving at the same time — while a + * second answer in a window it already spent still refuses. + */ + #spend(installation: object, open: ResolutionWindow): void { const spent = this.#spent.get(installation); if (spent === undefined) { this.#spent.set(installation, new WeakSet([open])); } else { spent.add(open); } - return answer; } /** @@ -611,21 +675,24 @@ export class CanonicalImports { if (claim === undefined) { return undefined; } - // The caller presents the resolution it opened, and the claim has to be an - // answer to *that* one, by object identity and under the name it decides. - // Nothing here consults the owner's current window: provenance read out of - // mutable state would be a claim about whenever the question was asked - // rather than about which import the statement answered. - if (claim.window !== resolution || claim.name !== resolution.name) { + // The caller presents the resolution it opened, and this answer has to have + // been claimed in *that* one, under the name it decides. Nothing here + // consults the owner's current window: provenance read out of mutable state + // would be a claim about whenever the question was asked rather than about + // which import the statement answered. A window that never claimed this + // answer holds no copy of it, whatever its siblings did. + if (claim.name !== resolution.name || !claim.copies.has(resolution)) { return undefined; } - // A claimed object the chain went on to edit is not the thing that was - // claimed. Reading it runs whatever it is made of, and a value that refuses - // to be compared has failed the comparison. - if (claim.canonical === undefined || !stillDescribes(claim.canonical, answer)) { + // This window's own copy, taken when it claimed. A claimed object the chain + // went on to edit is not the thing that was claimed: reading it runs + // whatever it is made of, and a value that refuses to be compared has + // failed the comparison. + const canonical = claim.copies.get(resolution); + if (canonical === undefined || !stillDescribes(canonical, answer)) { return undefined; } - return Object.freeze({ identity: claim.identity, definition: claim.canonical }); + return Object.freeze({ identity: claim.identity, definition: canonical }); } /** diff --git a/packages/core/src/document-validation.ts b/packages/core/src/document-validation.ts index ef8b19235..2090ca02e 100644 --- a/packages/core/src/document-validation.ts +++ b/packages/core/src/document-validation.ts @@ -317,6 +317,16 @@ interface LexicalContext { readonly insideIf: boolean; /** Whether a `` in this source lexically encloses this point. */ readonly insideSwitch: boolean; + /** + * Whether an `` in this source lexically encloses this point. + * + * Not the immediate parent: a `` written anywhere below an `` is + * that ``'s to report, because the shared structure analysis walks the + * whole region and anchors the diagnostic at the element. This is what tells + * such a spawn from one written with no `` above it at all, which is the + * only case the element's own rule owns. + */ + readonly insideAll: boolean; /** * Whether a `` in this source lexically encloses this point. * @@ -510,6 +520,7 @@ class ValidationState { entry, isRoot: entry.ordinal === 0, insideLoop: false, + insideAll: false, insideIf: false, insideSwitch: false, insideSpawn: false, @@ -1163,10 +1174,12 @@ class ValidationState { // reported wherever it was written, before any child could start. return allStructure(segment).violations; case "Spawn": - // A well-placed `` is its ``'s, and one placed wrongly - // under an `` is already reported by that ``'s own structure. - // What is left is a `` with no `` above it at all. - return context.enclosing === "All" + // Every `` below an `` belongs to that ``, wherever it + // was written: `allStructure()` walks the whole region and reports a + // misplaced one at the element it found, so a second report here would + // be the same sentence twice about one mistake. What is left is a + // `` with no `` above it at all. + return context.insideAll ? [] : [{ code: "structural-usage-invalid", source: "Spawn", message: straySpawnMessage() }]; case "Break": @@ -1372,6 +1385,9 @@ function childContext(segment: ComponentElement, context: LexicalContext): Lexic insideLoop: !spawned && (context.insideLoop || segment.name === "Loop"), insideIf: context.insideIf || segment.name === "If", insideSwitch: context.insideSwitch || segment.name === "Switch", + // Never cleared by a spawn: a nested `` owns its own descendants, and + // everything below the outermost one already has an owner. + insideAll: context.insideAll || segment.name === "All", insideSpawn: context.insideSpawn || spawned, underAnswers: segment.name === "Answers", enclosing: segment.name, diff --git a/packages/core/src/expand.ts b/packages/core/src/expand.ts index 1f563cc53..91d990248 100644 --- a/packages/core/src/expand.ts +++ b/packages/core/src/expand.ts @@ -2579,7 +2579,7 @@ function* expandComponent( // this invocation is in one of this execution's identity domains, and nothing // on the answer or in the chain carries it (`invocation-identity.ts`). // Opened under the scope this expansion is running in, which is what makes - // the frame this branch's own: a sibling `` resolving the same name at + // the frame this spawn's own: a sibling `` resolving the same name at // the same time opens its own, under its own scope. const selection = environment?.componentIdentity?.beginImport(name, yield* useScope()); let selected: IdentityDomain | undefined; diff --git a/packages/core/src/invocation-identity.ts b/packages/core/src/invocation-identity.ts index 696599812..dec0d62c1 100644 --- a/packages/core/src/invocation-identity.ts +++ b/packages/core/src/invocation-identity.ts @@ -396,7 +396,7 @@ export interface InvocationIdentities { * * The engine settles it as soon as that import answers, whatever the answer * was, so nothing a handler does in between decides what the frame holds — - * including an import another branch opened while this one was in flight. + * including an import a sibling spawn opened while this one was in flight. */ beginImport(name: string, scope: Scope): ImportSelection; /** @@ -1148,11 +1148,12 @@ export function installIdentities( * A stack per scope rather than one for the execution. Nesting inside one * scope is still LIFO — a handler may expand something of its own while an * import is in flight, and the inner import owns the top until it closes. - * What a single execution-wide stack could not express is *branching*: two - * `` children may each have an import open at the same time, and - * whichever pushed last would then receive the other's canonical selection. + * What a single execution-wide stack could not express is *spawned + * concurrency*: two `` children may each have an import open at the + * same time, and whichever pushed last would then receive the other's + * canonical selection. * One invocation would settle with no domain and the other with a domain it - * never selected, which is where an ordinary `` in each branch + * never selected, which is where an ordinary `` in each spawned child * stopped being able to name its own durable identity. * * The scope is a private key and nothing else. It is never published, never @@ -1177,9 +1178,9 @@ export function installIdentities( } return { settle(): IdentityDomain | undefined { - // Only this frame, and only from the scope that opened it: a - // sibling branch closing its own import may neither clear this one - // nor be cleared by it. + // Only this frame, and only from the scope that opened it: a sibling + // spawn closing its own import may neither clear this one nor be + // cleared by it. const stack = frames.get(scope); if (stack !== undefined) { const index = stack.lastIndexOf(frame); @@ -1199,7 +1200,7 @@ export function installIdentities( select(name: string, definition: FunctionComponentDefinition, scope: Scope): void { // The innermost import open in the scope that is resolving, which is // the one this selection answers. A selection never reaches another - // branch's frame, however the two happen to interleave. + // spawn's frame, however the two happen to interleave. const frame = frames.get(scope)?.at(-1); if (frame === undefined) { return; @@ -1220,7 +1221,7 @@ export function installIdentities( domain.revoke(); } // Every stack, not only the ones that emptied themselves: an execution - // torn down while a branch still had an import open leaves no frame + // torn down while a spawn still had an import open leaves no frame // behind for anything to select into. frames.clear(); // The route goes with the domains: a wrapper projected into it, or a diff --git a/packages/core/tests/all.test.ts b/packages/core/tests/all.test.ts index a1388c6a4..e2becf15a 100644 --- a/packages/core/tests/all.test.ts +++ b/packages/core/tests/all.test.ts @@ -927,6 +927,33 @@ describe("Tier ALL — PA7: malformed structure refuses before any child starts" }); } + it("ALL19b: non-executing validation reports one nested misplaced once", function* () { + const shared = harness(); + const source = [ + "", + '', + '', + "", + ].join("\n"); + yield* useComponents(shared); + // Validation rather than a run, because a refusal reports the first thing + // wrong and this row is about how many things are reported. + const validation = yield* validateDocument(inlineSource(source)); + const misplaced = validation.diagnostics.filter((diagnostic) => + diagnostic.message.includes("must be a direct child of "), + ); + // One owner, one diagnostic. The `` walks its whole region, so the + // element's own rule has nothing left to say about a spawn below an `` + // — and a reader told the same thing twice about one mistake looks for two. + expect(misplaced).toHaveLength(1); + // Anchored where it was written: the inner ``, not the `` that + // found it and not the `` it was written inside. + expect(misplaced[0]?.position?.line).toBe(2); + expect(misplaced[0]?.position?.column).toBe(29); + // Nothing ran to decide any of it. + expect(shared.ran).toEqual([]); + }); + it("ALL20: a repository file cannot supply or ", function* () { const shared = harness(); const result = yield* run("from a file", { @@ -1164,7 +1191,7 @@ describe("Tier ALL — PA9: the construct exists everywhere the language does", }); /** - * Tier PA10a/c — the Story's own example: ordinary `` in each branch. + * Tier PA10a/c — the Story's own example: an ordinary `` in each spawn. * * `` is a capability-backed identity component, so two of them running * at once is the case where canonical resolution has to attribute each answer @@ -1206,7 +1233,7 @@ function conversations(options: { gated?: boolean } = {}): Conversation { ...component, factory: (claim: Parameters[0]) => { // One implementation per declared component per execution, however many - // branches invoke it. A domain minted per `` would show up here. + // spawns invoke it. A domain minted per `` would show up here. built += 1; return component.factory(claim); }, @@ -1384,7 +1411,7 @@ describe("Tier PA10a — two ordinary Sessions at the same time", () => { expect(result.ok).toBe(true); // One declared component, one implementation, one provider installation - // serving both branches — not a domain per spawn. + // serving both spawns — not a domain per spawn. expect(held.sessions()).toBe(1); expect(held.activations()).toBe(1); @@ -1426,7 +1453,7 @@ describe("Tier PA10c — nesting and replay with ordinary Sessions", () => { expect(held.sessions()).toBe(1); const recorded = prompts(result.events); expect(recorded).toHaveLength(3); - // Hierarchical child identity, source-ordered: a branch inside a branch + // Hierarchical child identity, source-ordered: a spawn inside a spawn // owns its own frames as much as a top-level one does. expect(new Set(recorded.map((entry) => entry.coroutineId))).toEqual( new Set(["root.0.0", "root.0.1", "root.1"]), diff --git a/packages/core/tests/answer-identity.test.ts b/packages/core/tests/answer-identity.test.ts index f3e52cbf6..cfdb56d37 100644 --- a/packages/core/tests/answer-identity.test.ts +++ b/packages/core/tests/answer-identity.test.ts @@ -52,14 +52,14 @@ const OPEN = { key: "Open", revision: "1" } as const; const OTHER = { key: "Other", revision: "1" } as const; /** - * Where two branches wait for each other. + * Where two sibling spawns wait for each other. * * A window belongs to the engine scope that opened it, so the rows about two - * branches at once are written as two operations that each own their own scope - * and read it from inside. Nothing hands a `Scope` out of the operation that - * owns it, and a window never outlives the body that opened it. + * spawns at once are written as two operations that each own their own scope and + * read it from inside. Nothing hands a `Scope` out of the operation that owns + * it, and a window never outlives the body that opened it. * - * What is left is the coordination: both branches have to be *open together*, + * What is left is the coordination: both spawns have to be *open together*, * which is the whole point, and neither may run ahead. Each step is a counter * and one signal — the party that completes it releases everybody waiting on * it, and a step that never completes is reported as a deadlock rather than @@ -79,7 +79,7 @@ function rendezvous(parties: number): (step: string) => Operation { if (waiting.arrived >= parties) { waiting.reached.publish(); } - yield* awaiting(`both branches reaching "${step}"`, waiting.reached.published); + yield* awaiting(`both spawns reaching "${step}"`, waiting.reached.published); })(); }; } @@ -89,7 +89,7 @@ function rendezvous(parties: number): (step: string) => Operation { * before the wait is called a deadlock. * * Never reached by a passing run: every step below is completed by the other - * branch. It bounds only the failure mode, so a defect that stops one branch + * spawn. It bounds only the failure mode, so a defect that stops one spawn * says which step it stopped at instead of hanging the suite. */ const DEADLOCK_MS = 10_000; @@ -873,13 +873,13 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); /** - * Tier PA10b — two branches resolving at the same time. + * Tier PA10b — two sibling spawns resolving at the same time. * * `` lets two `` children have an import open together, so a * resolution is no longer the only one in flight. What makes an answer this * import's is the exact window it was asked in, and windows now belong to the * engine scope that opened them — so these rows are written with two real - * scopes standing for two branches, and never with one branch's bookkeeping + * scopes standing for two spawns, and never with one spawn's bookkeeping * standing in for the other's. */ describe("Tier PA10b — concurrent resolution windows", () => { @@ -890,9 +890,9 @@ describe("Tier PA10b — concurrent resolution windows", () => { const answers = new Map(); /** - * One branch, resolving in a scope of its own. + * One spawned child, resolving in a scope of its own. * - * Everything the branch owns is opened and settled inside this operation: + * Everything the spawn owns is opened and settled inside this operation: * it reads its own scope here, keeps its window and its request for as long * as the operation lasts, and hands nothing but its answer back. The two * run together under `all`, held at a rendezvous so neither can finish @@ -904,7 +904,7 @@ describe("Tier PA10b — concurrent resolution windows", () => { const here = yield* useScope(); const window = imports.beginResolution("Open", here); try { - // Both windows are open before either branch claims, which is the + // Both windows are open before either spawn claims, which is the // shape two `` children produce and the only arrangement in // which a claim could land in the wrong one. yield* meet("both open"); @@ -913,7 +913,7 @@ describe("Tier PA10b — concurrent resolution windows", () => { asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), ); yield* meet("claimed"); - // Both branches have answered and both windows are still open, so + // Both spawns have answered and both windows are still open, so // the cross-checks are made while the other one really exists. const mine = answers.get(name)!; const other = answers.get(name === "left" ? "right" : "left")!; @@ -931,7 +931,7 @@ describe("Tier PA10b — concurrent resolution windows", () => { expect(answers.get("left")).not.toBe(answers.get("right")); }); - it("PA10b: a request answers its own branch and refuses the sibling's", function* () { + it("PA10b: a request answers its own spawn and refuses the sibling's", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); const meet = rendezvous(2); @@ -1016,13 +1016,13 @@ describe("Tier PA10b — concurrent resolution windows", () => { expect(refused[0]).toBeInstanceOf(AnswerIdentityError); }); - it("PA10b: one branch ending leaves the other live, and teardown leaves neither", function* () { + it("PA10b: one spawn ending leaves the other live, and teardown leaves neither", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); const meet = rendezvous(2); const identified: unknown[] = []; - // This branch simply ends, which is what a spawn child answering, failing + // This spawn simply ends, which is what a spawned child answering, failing // or being cancelled looks like from the owner's side: its scope goes, and // with it every window it had open. const ending = scoped(function* (): Operation { @@ -1041,7 +1041,7 @@ describe("Tier PA10b — concurrent resolution windows", () => { try { yield* meet("both open"); yield* meet("the other ended"); - // Still deciding, and still claimable: the branch that ended neither + // Still deciding, and still claimable: the spawn that ended neither // cleared this window nor authorized anything in it. const still = asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); identified.push(imports.identify(window, still)?.identity); @@ -1070,7 +1070,7 @@ describe("Tier PA10b — concurrent resolution windows", () => { }); }); - it("PA10b: a nested resolution owns the top of its own branch until it closes", function* () { + it("PA10b: a nested resolution owns the top of its own spawn until it closes", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); @@ -1095,3 +1095,234 @@ describe("Tier PA10b — concurrent resolution windows", () => { }); }); }); + +/** + * Tier PA10c — one reusable provider, one definition, several imports. + * + * A provider that holds an immutable definition hands back the exact same object + * every time it answers. What that object *is* was settled once; which import it + * answered is settled per resolution. These rows use one shared reference, + * created once, so a ledger that made the first window part of the object's + * permanent claim refuses the second — which is the defect they exist to catch. + */ +describe("Tier PA10c — one definition answering more than one import", () => { + it("PA10c: the same definition answers a later import after the first window closed", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const here = yield* useScope(); + // One object, created once and never copied: this is what a provider that + // owns its definition hands to everybody who asks. + const shared = answer(); + + const first = resolving( + imports, + "Open", + (resolution) => { + const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN), here); + expect(supplied).toBe(shared); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + return resolution; + }, + here, + ); + + // The second import is a new resolution of the same name, after the first is + // over. The definition is the same object, and it is still this provider's + // answer to say. + resolvingLater(imports, provider, here, shared); + // And the closed window still reads the claim it recorded, unchanged by the + // later one: each resolution keeps its own. + expect(imports.identify(first, shared)?.identity).toEqual(IDENTITY); + }); + + it("PA10c: an edited definition cannot be claimed again, and identifies nowhere", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const here = yield* useScope(); + const shared = answer(); + + const first = resolving( + imports, + "Open", + (resolution) => { + asking(provider, "Open", (request) => request.claim(shared, OPEN), here); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + return resolution; + }, + here, + ); + + // One member of the definition, edited after it was claimed and while the + // stated identity says nothing changed. This is a different implementation + // wearing the first one's revision. + shared.props = { type: "object", properties: {}, additionalProperties: true }; + + resolving( + imports, + "Open", + (resolution) => { + asking( + provider, + "Open", + (request) => { + // Refused before anything is recorded: the identity was stated about + // the definition core retained, and this object is no longer it. + expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + return undefined; + }, + here, + ); + // So the new window vouches for nothing. + expect(imports.identify(resolution, shared)).toBe(undefined); + }, + here, + ); + // And the window that did claim it cannot identify the changed object + // either, which is the change detection that was already there. + expect(imports.identify(first, shared)).toBe(undefined); + }); + + it("PA10c: the same definition answers two imports open at the same time", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const meet = rendezvous(2); + const shared = answer(); + const identified = new Map(); + + /** One spawned child's import, opened and settled inside its own operation. */ + const resolve = (name: string) => + scoped(function* (): Operation { + const here = yield* useScope(); + const window = imports.beginResolution("Open", here); + try { + // Both windows are open before either claims, so neither claim can be + // the other's: this is the arrangement sibling spawns produce. + yield* meet("both open"); + const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN), here); + // The provider handed back its own object, not a copy of it. + expect(supplied).toBe(shared); + yield* meet("claimed"); + // Read while the sibling's window is still open, which is the only + // arrangement in which a shared ledger entry could answer for the + // wrong import. + identified.set(name, imports.identify(window, shared)?.identity); + yield* meet("checked"); + } finally { + window.close(); + } + }); + + yield* all([resolve("left"), resolve("right")]); + expect(identified.get("left")).toEqual(IDENTITY); + expect(identified.get("right")).toEqual(IDENTITY); + }); + + it("PA10c: reuse spends each window, so a different answer in one still refuses", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const here = yield* useScope(); + const shared = answer(); + + resolvingLater(imports, provider, here, shared); + // The same definition again in a fresh window is reuse; a *second* answer in + // that same window is two answers to one import, and that still refuses. + resolving( + imports, + "Open", + (resolution) => { + asking( + provider, + "Open", + (request) => { + expect(request.claim(shared, OPEN)).toBe(shared); + expect(refusalOf(() => request.claim(answer(), OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + return undefined; + }, + here, + ); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + }, + here, + ); + }); + + it("PA10c: a new window cannot rename the definition or take it for another provider", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const other = imports.provider("test://other"); + const here = yield* useScope(); + const shared = answer(); + + resolvingLater(imports, provider, here, shared); + // What this object is was settled by its first claim. A new resolution is a + // new question about which import it answered, never a chance to restate it. + resolving( + imports, + "Other", + (resolution) => { + asking( + provider, + "Other", + (request) => { + expect(refusalOf(() => request.claim(shared, OTHER))).toBeInstanceOf( + AnswerIdentityError, + ); + return undefined; + }, + here, + ); + expect(imports.identify(resolution, shared)).toBe(undefined); + }, + here, + ); + resolving( + imports, + "Open", + (resolution) => { + asking( + other, + "Open", + (request) => { + expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + return undefined; + }, + here, + ); + expect(imports.identify(resolution, shared)).toBe(undefined); + }, + here, + ); + }); +}); + +/** + * Claim one shared definition in a resolution of its own, and read it back. + * + * Written once because three rows need the same second import: a fresh window, + * the same object, and the same provider saying the same thing about it. All of + * it is synchronous bookkeeping, so it is a plain function — there is nothing + * here for an operation to wait on. + */ +function resolvingLater( + imports: CanonicalImports, + provider: ProviderInstallation, + scope: Scope, + shared: ImportedDefinition, +): void { + resolving( + imports, + "Open", + (resolution) => { + const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN), scope); + expect(supplied).toBe(shared); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + }, + scope, + ); +} diff --git a/packages/core/tests/invocation-identity.test.ts b/packages/core/tests/invocation-identity.test.ts index beef07b41..d37cf2808 100644 --- a/packages/core/tests/invocation-identity.test.ts +++ b/packages/core/tests/invocation-identity.test.ts @@ -181,11 +181,11 @@ function* seam(): Operation<{ claim: IdentityClaimant; domain: IdentityDomain }> if (claim === undefined || registration === undefined) { throw new Error("the seam produced no claimant"); } - // The seam's own scope, because this seam is not about branching: a frame + // The seam's own scope, because this seam is not about spawned work: a frame // belongs to the engine scope that opened it, and this one already runs in a // scope its caller owns. - const branch = yield* useScope(); - const frame = installed.identities.beginImport("Both", branch); + const here = yield* useScope(); + const frame = installed.identities.beginImport("Both", here); installed.identities.select( "Both", { @@ -194,7 +194,7 @@ function* seam(): Operation<{ claim: IdentityClaimant; domain: IdentityDomain }> props: NO_PROPS, fn: registration.fn, }, - branch, + here, ); const domain = frame.settle(); if (domain === undefined) { @@ -1038,12 +1038,12 @@ describe("Tier CIV — the authored form on the invocation", () => { }); /** - * Tier PA10b — one declared component, two branches at once. + * Tier PA10b — one declared component, two sibling spawns at once. * * `` gives two `` children imports in flight together. What puts an * invocation in this execution's identity domain is the canonical selection * made inside the frame its own import opened — so these rows are the general - * statement of the thing an ordinary `` in each branch needs. + * statement of the thing an ordinary `` in each spawn needs. */ describe("Tier PA10b — concurrent capability-backed identity", () => { it("PA10b: two concurrent sites each claim their own identity, exactly once", function* () { @@ -1081,8 +1081,8 @@ describe("Tier PA10b — concurrent capability-backed identity", () => { nothing, ); - // Three sites, three identities, no refusal: a branch nested inside a - // branch owns its own frames as much as a top-level one does. + // Three sites, three identities, no refusal: a spawn nested inside a + // spawn owns its own frames as much as a top-level one does. expect(seen.refusals).toEqual([]); expect(seen.taken).toHaveLength(3); expect(new Set(seen.taken).size).toBe(3); diff --git a/specs/executable-mdx-spec.md b/specs/executable-mdx-spec.md index 3539ccc16..6d5456e0c 100644 --- a/specs/executable-mdx-spec.md +++ b/specs/executable-mdx-spec.md @@ -5500,16 +5500,17 @@ happen, happened twice, or answered for a name the engine did not ask. An import frame belongs to the Effection scope that opened it, and each scope keeps its own innermost-last stack of them. Nesting inside one scope is unchanged: an inner import owns the top until it closes, after which the outer -one may be selected into again. What the ownership adds is branching. Two -`` children under one `` may have imports open at the same time, and -each one's canonical selection is recorded into its own branch's frame — so an +one may be selected into again. What the ownership adds is spawned concurrency. +Two `` children under one `` may have imports open at the same time, +and each one's canonical selection is recorded into its own spawn's frame — so an ordinary `` written in each child receives its own authentic identity, -neither child can be handed the other's, and closing or cancelling one branch +neither child can be handed the other's, and closing or cancelling one spawn neither clears nor authorizes the other. Two selections in one frame still settle to nothing. The engine holds one domain per declared component per -execution however many branches invoke it, and the same ownership governs the +execution however many spawns invoke it, and the same ownership governs the windows a provider's claim is admitted in: one installation may answer in two -branches at once, while a second, different answer in either refuses. +sibling spawns at once, and may answer with the exact same definition in each, +while a second, *different* answer in either refuses. Forwarding the genuine issuance is ordinary delegation and stays supported; everything else refuses. None of it reads replaceable state, so middleware may short-circuit an import, redirect a name, replace a definition, shadow a From 6da61ba66eed3f599e5da1fecdf34dc8cefdc07a Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 08:53:00 -0400 Subject: [PATCH 05/12] =?UTF-8?q?=E2=9A=A1=20Measure=20test=20weights=20at?= =?UTF-8?q?=20dcc94680?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test-weights.json | 2158 ++++++++++++++++++++++----------------------- 1 file changed, 1079 insertions(+), 1079 deletions(-) diff --git a/test-weights.json b/test-weights.json index 6f8199aec..dcb46f621 100644 --- a/test-weights.json +++ b/test-weights.json @@ -1,8 +1,8 @@ { "version": 1, "source": { - "commit": "b14a2ba145364f38604cadba373f40a411242899", - "runUrl": "https://github.com/taras/executable.md/actions/runs/36473005680", + "commit": "dcc9468073ad005a241e6990e513e08b4cfeec86", + "runUrl": "https://github.com/taras/executable.md/actions/runs/36508610515", "attempt": 1, "runner": "ubuntu-latest", "deno": "deno 2.9.5 (stable, release, x86_64-unknown-linux-gnu)", @@ -11,1097 +11,1097 @@ }, "runtimes": { "deno": { - "packages/acp/tests/acceptance.test.ts": 5139, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 8515, - "packages/acp/tests/acpx-materialization.test.ts": 8150, - "packages/acp/tests/acpx-transient-env.test.ts": 1821, - "packages/acp/tests/adapter-materialization.test.ts": 78988, - "packages/acp/tests/adapter-protocol.test.ts": 61601, - "packages/acp/tests/codex-surfaces.test.ts": 1833, - "packages/acp/tests/loaded-copy.test.ts": 4786, - "packages/acp/tests/native-launch.test.ts": 5474, - "packages/acp/tests/permission-bridge.test.ts": 4275, - "packages/acp/tests/provider.test.ts": 5379, - "packages/acp/tests/serial-queue.test.ts": 1623, - "packages/acp/tests/session-key.test.ts": 4052, - "packages/acp/tests/session-route.test.ts": 4267, - "packages/acp/tests/terminal-screen.test.ts": 1764, - "packages/cli/tests/agent-adapters.test.ts": 5788, - "packages/cli/tests/agent-cli.test.ts": 38729, - "packages/cli/tests/agent-config.test.ts": 3784, - "packages/cli/tests/agent-options-cli.test.ts": 15983, - "packages/cli/tests/agent-options.test.ts": 3813, - "packages/cli/tests/agent-session-coordinator.test.ts": 4499, - "packages/cli/tests/cli-help.test.ts": 20957, - "packages/cli/tests/command.test.ts": 10570, - "packages/cli/tests/compiled-upgrade.test.ts": 11276, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 9268, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 122402, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 8908, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 12657, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 10782, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 15941, - "packages/cli/tests/evaluate-component.test.ts": 12222, - "packages/cli/tests/evaluate-workflow.test.ts": 5866, - "packages/cli/tests/fetch-cli.test.ts": 3906, - "packages/cli/tests/file-stream.test.ts": 1856, - "packages/cli/tests/github-zero-effect.test.ts": 7422, - "packages/cli/tests/inline-cli.test.ts": 34156, - "packages/cli/tests/launch-timeout.test.ts": 11644, - "packages/cli/tests/packaged-document.test.ts": 5037, - "packages/cli/tests/plan-args.test.ts": 1582, - "packages/cli/tests/plan-cli.test.ts": 102307, - "packages/cli/tests/plan-command-document.test.ts": 10266, - "packages/cli/tests/plan-component.test.ts": 12588, - "packages/cli/tests/plan-host-acts.test.ts": 5568, - "packages/cli/tests/plan.test.ts": 16769, - "packages/cli/tests/plugin-cli.test.ts": 41879, - "packages/cli/tests/plugin-host.test.ts": 6332, - "packages/cli/tests/plugin-modules.test.ts": 1556, - "packages/cli/tests/plugin-selection.test.ts": 1561, - "packages/cli/tests/process-retention.test.ts": 5510, - "packages/cli/tests/props-cli.test.ts": 31508, - "packages/cli/tests/props-schema.test.ts": 4225, - "packages/cli/tests/props-sources.test.ts": 2454, - "packages/cli/tests/pull-request-read-fork.test.ts": 7419, - "packages/cli/tests/repl-boundaries.test.ts": 7821, - "packages/cli/tests/repl-composition.test.ts": 2141, - "packages/cli/tests/repl-execution.test.ts": 5669, - "packages/cli/tests/repl-journey.test.ts": 20829, - "packages/cli/tests/repl-model.test.ts": 5524, - "packages/cli/tests/repl-route.test.ts": 5007, - "packages/cli/tests/repl-terminal.test.ts": 2992, - "packages/cli/tests/run-composition-deno.test.ts": 8299, - "packages/cli/tests/run-composition-nested.test.ts": 21878, - "packages/cli/tests/run-composition.test.ts": 7301, - "packages/cli/tests/run-deadline.test.ts": 9041, - "packages/cli/tests/run-profile.test.ts": 4530, - "packages/cli/tests/run-timeouts.test.ts": 13412, - "packages/cli/tests/secret-detection-cli.test.ts": 20200, - "packages/cli/tests/service-document.test.ts": 5466, - "packages/cli/tests/service-host.test.ts": 5372, - "packages/cli/tests/session-launch-cli.test.ts": 10990, - "packages/cli/tests/stdin-cli.test.ts": 38532, - "packages/cli/tests/stdout-delivery.test.ts": 1616, - "packages/cli/tests/syntax-cli.test.ts": 37953, - "packages/cli/tests/targets-cli.test.ts": 30055, - "packages/cli/tests/test-root-profile.test.ts": 7519, - "packages/cli/tests/test-target.test.ts": 38653, - "packages/cli/tests/testing-activation.test.ts": 4672, - "packages/cli/tests/testing-execution-host.test.ts": 58524, - "packages/cli/tests/upgrade-cli.test.ts": 21591, - "packages/cli/tests/upgrade-command-document.test.ts": 7600, - "packages/cli/tests/upgrade-output.test.ts": 4756, - "packages/cli/tests/value-root.test.ts": 18176, - "packages/cli/tests/verbose-component.test.ts": 5065, - "packages/cli/tests/workflow-agent-sessions.test.ts": 20012, - "packages/cli/tests/workflow-agent.test.ts": 16243, - "packages/cli/tests/workflow-cli.test.ts": 110048, - "packages/cli/tests/workflow-crash.test.ts": 81682, - "packages/cli/tests/workflow-declaration.test.ts": 4738, - "packages/cli/tests/workflow-export-publication.test.ts": 18109, - "packages/cli/tests/workflow-fetch.test.ts": 8495, - "packages/cli/tests/workflow-fork.test.ts": 89126, - "packages/cli/tests/workflow-host.test.ts": 15299, - "packages/cli/tests/workflow-inspection.test.ts": 121028, - "packages/cli/tests/workflow-installation.test.ts": 6511, - "packages/cli/tests/workflow-lifecycle-control.test.ts": 21497, - "packages/cli/tests/workflow-retention.test.ts": 24271, - "packages/cli/tests/workflow-suspension.test.ts": 8453, - "packages/code-review-agent/tests/doctor.test.ts": 1592, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 1690, - "packages/code-review-agent/tests/parse-diff.test.ts": 1609, - "packages/code-review-agent/tests/parse-doctor.test.ts": 4194, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 1592, - "packages/code-review-agent/tests/policy.test.ts": 1583, - "packages/core/tests/agent-api.test.ts": 1621, - "packages/core/tests/agent-components.test.ts": 4835, - "packages/core/tests/agent-function-components.test.ts": 6755, - "packages/core/tests/agent-session-launch.test.ts": 7039, - "packages/core/tests/agent-session-placement.test.ts": 1664, - "packages/core/tests/agent-session-use-loaded-copy.test.ts": 1701, - "packages/core/tests/agent-session-use.test.ts": 1642, - "packages/core/tests/agent-stack.test.ts": 4370, - "packages/core/tests/all.test.ts": 5461, - "packages/core/tests/answer-identity.test.ts": 3824, - "packages/core/tests/answers-component.test.ts": 5020, - "packages/core/tests/answers-expansion-recursion.test.ts": 3970, - "packages/core/tests/capture-errors.test.ts": 4234, - "packages/core/tests/capture-props.test.ts": 4093, - "packages/core/tests/cli-journal.test.ts": 12679, - "packages/core/tests/code-block-component.test.ts": 5603, - "packages/core/tests/compiler-boundary.test.ts": 4006, - "packages/core/tests/component-api.test.ts": 3752, - "packages/core/tests/component-registration.test.ts": 4910, - "packages/core/tests/component-returns.test.ts": 5391, - "packages/core/tests/component-schema-conformance.test.ts": 4169, - "packages/core/tests/config-api.test.ts": 4185, - "packages/core/tests/construct-error-observation.test.ts": 4314, - "packages/core/tests/contextual-cwd.test.ts": 5334, - "packages/core/tests/daemon-integration.test.ts": 4811, - "packages/core/tests/daemon.test.ts": 3803, - "packages/core/tests/declared-markdown-component.test.ts": 5582, - "packages/core/tests/document-output-api.test.ts": 1607, - "packages/core/tests/document-target-execution.test.ts": 7060, - "packages/core/tests/document-targets.test.ts": 4228, - "packages/core/tests/document-validation.test.ts": 5698, - "packages/core/tests/documentation-index.test.ts": 3845, - "packages/core/tests/each.test.ts": 4277, - "packages/core/tests/elicit-component.test.ts": 4768, - "packages/core/tests/ephemeral-service.test.ts": 4641, - "packages/core/tests/eval-bindings.test.ts": 4120, - "packages/core/tests/eval-context.test.ts": 2287, - "packages/core/tests/eval-durable.test.ts": 4160, - "packages/core/tests/eval-error-mode.test.ts": 4464, - "packages/core/tests/eval-interpolate.test.ts": 1560, - "packages/core/tests/eval-middleware.test.ts": 3769, - "packages/core/tests/eval-persist.test.ts": 4280, - "packages/core/tests/eval-return.test.ts": 4150, - "packages/core/tests/eval-scope.test.ts": 4142, - "packages/core/tests/eval-timeout.test.ts": 4131, - "packages/core/tests/eval-transform.test.ts": 3814, - "packages/core/tests/evaluate-component.test.ts": 6263, - "packages/core/tests/evaluate-loaded-copy.test.ts": 4282, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 4287, - "packages/core/tests/evaluation-profile.test.ts": 3859, - "packages/core/tests/exec-timeout.test.ts": 4191, - "packages/core/tests/execute.test.ts": 4727, - "packages/core/tests/execution-protocol.test.ts": 5587, - "packages/core/tests/expand.test.ts": 4965, - "packages/core/tests/expansion-identity.test.ts": 4799, - "packages/core/tests/expansion-metadata.test.ts": 4095, - "packages/core/tests/expression-props.test.ts": 4719, - "packages/core/tests/fail-component.test.ts": 4384, - "packages/core/tests/failure-printing.test.ts": 4361, - "packages/core/tests/fatal-cause.test.ts": 3923, - "packages/core/tests/fetch-component.test.ts": 5500, - "packages/core/tests/file-component.test.ts": 5958, - "packages/core/tests/file-delete-component.test.ts": 4211, - "packages/core/tests/files-fatal.test.ts": 4941, - "packages/core/tests/foreground-exec.test.ts": 5001, - "packages/core/tests/frontmatter.test.ts": 3665, - "packages/core/tests/function-components.test.ts": 4580, - "packages/core/tests/generated-composition.test.ts": 4553, - "packages/core/tests/generated-xmd.test.ts": 6067, - "packages/core/tests/glob-api.test.ts": 1918, - "packages/core/tests/glob-component.test.ts": 4672, - "packages/core/tests/guarded-journal.test.ts": 4010, - "packages/core/tests/has-content.test.ts": 3801, - "packages/core/tests/heal.test.ts": 3773, - "packages/core/tests/if.test.ts": 4496, - "packages/core/tests/inline-root.test.ts": 4020, - "packages/core/tests/invocation-failures.test.ts": 3737, - "packages/core/tests/invocation-identity.test.ts": 4464, - "packages/core/tests/invocation-scope.test.ts": 4005, - "packages/core/tests/journal-source-position.test.ts": 4210, - "packages/core/tests/json-component.test.ts": 4212, - "packages/core/tests/json.test.ts": 3675, - "packages/core/tests/let.test.ts": 4065, - "packages/core/tests/loaded-copy-files.test.ts": 3964, - "packages/core/tests/loop.test.ts": 4860, - "packages/core/tests/named-slots.test.ts": 4848, - "packages/core/tests/output-error-mode.test.ts": 5081, - "packages/core/tests/output-normalize.test.ts": 1533, - "packages/core/tests/output-terminal.test.ts": 1667, - "packages/core/tests/parse-components.test.ts": 4165, - "packages/core/tests/plan-response.test.ts": 1584, - "packages/core/tests/plugin-api.test.ts": 3605, - "packages/core/tests/plugin.test.ts": 3814, - "packages/core/tests/props-binding.test.ts": 4146, - "packages/core/tests/protected-content.test.ts": 3613, - "packages/core/tests/registered-printed-errors.test.ts": 3833, - "packages/core/tests/replay-stream.test.ts": 1542, - "packages/core/tests/retain.test.ts": 3994, - "packages/core/tests/root-composition.test.ts": 4156, - "packages/core/tests/root-props.test.ts": 4098, - "packages/core/tests/root-provider.test.ts": 4171, - "packages/core/tests/sample-component.test.ts": 4864, - "packages/core/tests/scanner.test.ts": 3655, - "packages/core/tests/scope-local.test.ts": 1562, - "packages/core/tests/secret-detection.test.ts": 4896, - "packages/core/tests/secret-files.test.ts": 2079, - "packages/core/tests/secret-rules.test.ts": 2080, - "packages/core/tests/secret-scanner-baseline.test.ts": 1750, - "packages/core/tests/secret-scanner.test.ts": 1923, - "packages/core/tests/source-position.test.ts": 3948, - "packages/core/tests/state-ownership.test.ts": 3981, - "packages/core/tests/streaming-emission.test.ts": 3980, - "packages/core/tests/switch.test.ts": 4647, - "packages/core/tests/syntax-catalog.test.ts": 4755, - "packages/core/tests/syntax-component.test.ts": 5476, - "packages/core/tests/syntax-loaded-copy.test.ts": 4125, - "packages/core/tests/temp-dir.test.ts": 6491, - "packages/core/tests/temp-file-compiler.test.ts": 2234, - "packages/core/tests/text-interpolation.test.ts": 3885, - "packages/core/tests/try-content.test.ts": 3827, - "packages/core/tests/unused-in-diff.test.ts": 4144, - "packages/core/tests/validate.test.ts": 3881, - "packages/core/tests/validation-integration.test.ts": 4029, - "packages/core/tests/workflow-component-bundle.test.ts": 4296, - "packages/durable-streams/tests/context.test.ts": 1828, - "packages/durable-streams/tests/deterministic-id.test.ts": 1872, - "packages/durable-streams/tests/divergence-api.test.ts": 1833, - "packages/durable-streams/tests/divergence.test.ts": 1910, - "packages/durable-streams/tests/durable-each.test.ts": 1908, - "packages/durable-streams/tests/durable-position.test.ts": 1868, - "packages/durable-streams/tests/durable-run.test.ts": 1897, - "packages/durable-streams/tests/ephemeral.test.ts": 1875, - "packages/durable-streams/tests/fail-stop.test.ts": 1903, - "packages/durable-streams/tests/guard-stream.test.ts": 1935, - "packages/durable-streams/tests/live-coordinator.test.ts": 1864, - "packages/durable-streams/tests/parse.test.ts": 1844, - "packages/durable-streams/tests/replay-guard.test.ts": 1973, - "packages/durable-streams/tests/replay-index.test.ts": 1667, - "packages/durable-streams/tests/retained.test.ts": 1767, - "packages/durable-streams/tests/serialize-event.test.ts": 1853, - "packages/durable-streams/tests/smoke.test.ts": 1847, - "packages/durable-streams/tests/structured-concurrency.test.ts": 1960, - "packages/durable-streams/tests/terminal-boundary.test.ts": 1913, - "packages/durable-streams/tests/types.test.ts": 1500, - "packages/git/tests/ambient-authentication.test.ts": 27928, - "packages/git/tests/api-entrypoint.test.ts": 5273, - "packages/git/tests/credential-helper.test.ts": 6302, - "packages/git/tests/git-add-crash.test.ts": 7199, - "packages/git/tests/git-add-durability.test.ts": 28169, - "packages/git/tests/git-add.test.ts": 37551, - "packages/git/tests/git-commit-crash.test.ts": 7598, - "packages/git/tests/git-commit-durability.test.ts": 35375, - "packages/git/tests/git-commit.test.ts": 43544, - "packages/git/tests/git-host-effect.test.ts": 9220, - "packages/git/tests/git-push-crash.test.ts": 10522, - "packages/git/tests/git-push-durability.test.ts": 47327, - "packages/git/tests/git-push.test.ts": 53042, - "packages/git/tests/git-switch-crash.test.ts": 7169, - "packages/git/tests/git-switch-durability.test.ts": 22374, - "packages/git/tests/git-switch.test.ts": 23500, - "packages/git/tests/git.test.ts": 4462, - "packages/git/tests/github-activation.test.ts": 5728, - "packages/git/tests/github-issues.test.ts": 4392, - "packages/git/tests/github-pull-requests.test.ts": 4024, - "packages/git/tests/github-workflow-activation.test.ts": 6038, - "packages/git/tests/issue-markdown.test.ts": 11613, - "packages/git/tests/issue-records.test.ts": 4343, - "packages/git/tests/materialization.test.ts": 5083, - "packages/git/tests/module-partition.test.ts": 5406, - "packages/git/tests/plugin.test.ts": 4764, - "packages/git/tests/provider-neutrality.test.ts": 3523, - "packages/git/tests/public-entrypoint.test.ts": 9694, - "packages/git/tests/pull-request-crash.test.ts": 8613, - "packages/git/tests/pull-request-durability.test.ts": 42143, - "packages/git/tests/pull-request-read.test.ts": 8263, - "packages/git/tests/pull-request-records.test.ts": 4320, - "packages/git/tests/pull-request.test.ts": 74015, - "packages/git/tests/repository-components.test.ts": 13059, - "packages/git/tests/repository-control-plane.test.ts": 11699, - "packages/git/tests/repository-materialization.test.ts": 8691, - "packages/git/tests/repository-replay.test.ts": 16427, - "packages/git/tests/repository-storage.test.ts": 20373, - "packages/git/tests/run-composition-ambient.test.ts": 13487, - "packages/git/tests/run-composition-lazy.test.ts": 5943, - "packages/git/tests/run-composition-managed.test.ts": 15967, - "packages/git/tests/run-composition-remote.test.ts": 16212, - "packages/git/tests/selection-authentication.test.ts": 1889, - "packages/git/tests/worktree-replay.test.ts": 7287, - "packages/runtime/tests/agent-session-coordinator.test.ts": 2293, - "packages/runtime/tests/duration.test.ts": 1569, - "packages/runtime/tests/executable-observer.test.ts": 1971, - "packages/runtime/tests/fetch.test.ts": 2451, - "packages/runtime/tests/fs.test.ts": 1767, - "packages/runtime/tests/host-files.test.ts": 2621, - "packages/runtime/tests/native-launcher.test.ts": 4020, - "packages/runtime/tests/process.test.ts": 1791, - "packages/runtime/tests/service.test.ts": 1906, - "packages/test-agent/tests/acp-server.test.ts": 1738, - "packages/test-agent/tests/behavior-engine.test.ts": 4396, - "packages/test-agent/tests/bridge.test.ts": 3921, - "packages/test-agent/tests/command-lazy.test.ts": 8254, - "packages/test-agent/tests/components.test.ts": 63092, - "packages/test-agent/tests/controller.test.ts": 3051, - "packages/test-agent/tests/cross-package-resolution.test.ts": 6405, - "packages/test-agent/tests/native-launch.test.ts": 32011, - "packages/test-agent/tests/net.test.ts": 1659, - "packages/test-agent/tests/profile.test.ts": 4172, - "packages/test-agent/tests/protocol.test.ts": 2553, - "packages/test-agent/tests/provider.test.ts": 4566, - "packages/test-agent/tests/public-api.test.ts": 5254, - "packages/test-agent/tests/route-slot.test.ts": 1621, - "packages/test-agent/tests/smoke.test.ts": 21659, - "packages/test-agent/tests/template.test.ts": 4152, - "packages/test-agent/tests/worker-lifecycle.test.ts": 13928, - "packages/test-support/tests/journal.test.ts": 1902, - "packages/testing/tests/agent-composition.test.ts": 4483, - "packages/testing/tests/assert-throws.test.ts": 5864, - "packages/testing/tests/assert.test.ts": 1572, - "packages/testing/tests/assertions.test.ts": 6323, - "packages/testing/tests/boundary-contract.test.ts": 5297, - "packages/testing/tests/cli.test.ts": 7146, - "packages/testing/tests/execution-harness.test.ts": 9300, - "packages/testing/tests/replay.test.ts": 5798, - "packages/testing/tests/smoke.test.ts": 5991, - "packages/testing/tests/test-component.test.ts": 6419, - "packages/testing/tests/testing-activation.test.ts": 6036, - "packages/testing/tests/testing-boundary.test.ts": 4938, - "packages/testing/tests/testing-mode.test.ts": 6447, - "packages/testing/tests/use-testing.test.ts": 5495, - "packages/web/tests/assets.test.ts": 1693, - "packages/web/tests/client-logic.test.ts": 1668, - "packages/web/tests/compile.test.ts": 4897, - "packages/web/tests/component.test.ts": 5479, - "packages/web/tests/declaration.test.ts": 4662, - "packages/web/tests/document.test.ts": 5014, - "packages/web/tests/elicitation.test.ts": 4650, - "packages/web/tests/live-form.test.ts": 4546, - "packages/web/tests/markdown.test.ts": 1815, - "packages/web/tests/opener.test.ts": 4579, - "packages/web/tests/page.test.ts": 1635, - "packages/web/tests/responder.test.ts": 4831, - "packages/web/tests/server-lifecycle.test.ts": 4664, - "packages/web/tests/server.test.ts": 4997, - "packages/workflow/tests/generated-agent-component.test.ts": 7215, - "packages/workflow/tests/generated-observations.test.ts": 4282, - "packages/workflow/tests/public-entrypoint.test.ts": 6231, - "packages/workflow/tests/retained-run.test.ts": 5131, - "packages/workflow/tests/service-denial.test.ts": 1846, - "packages/workflow/tests/workflow-agent-checkpoints.test.ts": 6138, - "packages/workflow/tests/workflow-agent-sessions.test.ts": 5087, - "packages/workflow/tests/workflow-bundle.test.ts": 4470, - "packages/workflow/tests/workflow-checkpoint.test.ts": 6169, - "packages/workflow/tests/workflow-definition.test.ts": 4316, - "packages/workflow/tests/workflow-export.test.ts": 8206, - "packages/workflow/tests/workflow-fork-source.test.ts": 5146, - "packages/workflow/tests/workflow-fork.test.ts": 4139, - "packages/workflow/tests/workflow-lifecycle-authority.test.ts": 6080, - "packages/workflow/tests/workflow-lifecycle-control.test.ts": 6693, - "packages/workflow/tests/workflow-lifecycle-inspection.test.ts": 11366, - "packages/workflow/tests/workflow-run-journal.test.ts": 7255, - "packages/workflow/tests/workflow-run-storage.test.ts": 8326, - "packages/workflow/tests/workflow-run.test.ts": 5036, - "packages/workflow/tests/workflow-suspension-answer.test.ts": 6020, - "packages/workflow/tests/workflow-suspension.test.ts": 5656, - "packages/workflow/tests/workspace-crash-recovery.test.ts": 8091, - "packages/workflow/tests/workspace-effect-loaded-copy.test.ts": 5202, - "packages/workflow/tests/workspace-effect-transaction.test.ts": 6074, - "packages/workflow/tests/workspace-effect.test.ts": 5994, - "packages/workflow/tests/workspace-files.test.ts": 13129, - "packages/workflow/tests/workspace-root-restoration.test.ts": 6777, - "packages/workflow/tests/workspace-root.test.ts": 5179, - "packages/workflow/tests/workspace-transaction.test.ts": 5177, - "packages/workflow/tests/xmd-artifact.test.ts": 6999, - "scripts/tests/acpx-vendor.test.ts": 2129, - "scripts/tests/adapter-distribution.test.ts": 4591, - "scripts/tests/adapter-npm-package.test.ts": 34653, - "scripts/tests/adapter-vendor.test.ts": 4109, - "scripts/tests/bootstrap-npm-package.test.ts": 11757, - "scripts/tests/build-npm.test.ts": 42015, - "scripts/tests/build-web-client.test.ts": 31713, - "scripts/tests/bump-version.test.ts": 1674, - "scripts/tests/changed-paths.test.ts": 1567, - "scripts/tests/ci-workflow.test.ts": 4994, - "scripts/tests/cli-npm-bin.test.ts": 262615, - "scripts/tests/cloudflare-dofs-vendor.test.ts": 4432, - "scripts/tests/consumer-cycle.test.ts": 1675, - "scripts/tests/documentation-validation.test.ts": 6375, - "scripts/tests/filesystem-contract-workflow.test.ts": 1599, - "scripts/tests/frozen-entry.test.ts": 7979, - "scripts/tests/jsr-consumer-documentation.test.ts": 18585, - "scripts/tests/main-green.test.ts": 1929, - "scripts/tests/main-health.test.ts": 1746, - "scripts/tests/measure-test-weights.test.ts": 2021, - "scripts/tests/no-module-scoped-registry.test.ts": 2418, - "scripts/tests/no-redundant-test-scope.test.ts": 6617, - "scripts/tests/no-sync-filesystem.test.ts": 6464, - "scripts/tests/no-yield-in-finally.test.ts": 2410, - "scripts/tests/oxlint-policy.test.ts": 12273, - "scripts/tests/packaged-document.test.ts": 1632, - "scripts/tests/prefer-effection-operation.test.ts": 7621, - "scripts/tests/prefer-effection-result.test.ts": 5722, - "scripts/tests/prepared-state.test.ts": 2780, - "scripts/tests/publish-workflow-generator.test.ts": 6190, - "scripts/tests/publish-workflow-membership.test.ts": 1732, - "scripts/tests/publishable-membership-agreement.test.ts": 4098, - "scripts/tests/readme-targets.test.ts": 19003, - "scripts/tests/release-targets.test.ts": 1621, - "scripts/tests/review-infrastructure.test.ts": 6242, - "scripts/tests/runtime-exclusions.test.ts": 2055, - "scripts/tests/runtime-tests.test.ts": 1690, - "scripts/tests/scope-bound-event-registration.test.ts": 6271, - "scripts/tests/shard-execution.test.ts": 11427, - "scripts/tests/staged-write.test.ts": 1561, - "scripts/tests/test-file-discovery.test.ts": 1835, - "scripts/tests/test-shards.test.ts": 1593, - "scripts/tests/test-weights.test.ts": 1829, - "scripts/tests/tracked.test.ts": 1563, - "scripts/tests/verify-adapter.test.ts": 7638, - "scripts/tests/verify-clean.test.ts": 1756, - "scripts/tests/verify-coordinator.test.ts": 1932, - "scripts/tests/version-lockstep.test.ts": 1757, - "scripts/tests/web-client-module.test.ts": 1536, - "scripts/tests/workspace.test.ts": 1558 + "packages/acp/tests/acceptance.test.ts": 4925, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 7995, + "packages/acp/tests/acpx-materialization.test.ts": 7998, + "packages/acp/tests/acpx-transient-env.test.ts": 1713, + "packages/acp/tests/adapter-materialization.test.ts": 74834, + "packages/acp/tests/adapter-protocol.test.ts": 57230, + "packages/acp/tests/codex-surfaces.test.ts": 1705, + "packages/acp/tests/loaded-copy.test.ts": 4323, + "packages/acp/tests/native-launch.test.ts": 5024, + "packages/acp/tests/permission-bridge.test.ts": 3891, + "packages/acp/tests/provider.test.ts": 4931, + "packages/acp/tests/serial-queue.test.ts": 1469, + "packages/acp/tests/session-key.test.ts": 3734, + "packages/acp/tests/session-route.test.ts": 3924, + "packages/acp/tests/terminal-screen.test.ts": 1611, + "packages/cli/tests/agent-adapters.test.ts": 5252, + "packages/cli/tests/agent-cli.test.ts": 37916, + "packages/cli/tests/agent-config.test.ts": 3446, + "packages/cli/tests/agent-options-cli.test.ts": 15255, + "packages/cli/tests/agent-options.test.ts": 3457, + "packages/cli/tests/agent-session-coordinator.test.ts": 4141, + "packages/cli/tests/cli-help.test.ts": 20080, + "packages/cli/tests/command.test.ts": 10127, + "packages/cli/tests/compiled-upgrade.test.ts": 10098, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 8406, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 117411, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 7894, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 11311, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 9687, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 14586, + "packages/cli/tests/evaluate-component.test.ts": 11213, + "packages/cli/tests/evaluate-workflow.test.ts": 5148, + "packages/cli/tests/fetch-cli.test.ts": 3710, + "packages/cli/tests/file-stream.test.ts": 1695, + "packages/cli/tests/github-zero-effect.test.ts": 6789, + "packages/cli/tests/inline-cli.test.ts": 32124, + "packages/cli/tests/launch-timeout.test.ts": 11544, + "packages/cli/tests/packaged-document.test.ts": 4560, + "packages/cli/tests/plan-args.test.ts": 1475, + "packages/cli/tests/plan-cli.test.ts": 98305, + "packages/cli/tests/plan-command-document.test.ts": 9251, + "packages/cli/tests/plan-component.test.ts": 11401, + "packages/cli/tests/plan-host-acts.test.ts": 5136, + "packages/cli/tests/plan.test.ts": 15053, + "packages/cli/tests/plugin-cli.test.ts": 39337, + "packages/cli/tests/plugin-host.test.ts": 5721, + "packages/cli/tests/plugin-modules.test.ts": 1491, + "packages/cli/tests/plugin-selection.test.ts": 1462, + "packages/cli/tests/process-retention.test.ts": 5320, + "packages/cli/tests/props-cli.test.ts": 29643, + "packages/cli/tests/props-schema.test.ts": 3853, + "packages/cli/tests/props-sources.test.ts": 2168, + "packages/cli/tests/pull-request-read-fork.test.ts": 6972, + "packages/cli/tests/repl-boundaries.test.ts": 7126, + "packages/cli/tests/repl-composition.test.ts": 1973, + "packages/cli/tests/repl-execution.test.ts": 5120, + "packages/cli/tests/repl-journey.test.ts": 20282, + "packages/cli/tests/repl-model.test.ts": 4895, + "packages/cli/tests/repl-route.test.ts": 4539, + "packages/cli/tests/repl-terminal.test.ts": 2802, + "packages/cli/tests/run-composition-deno.test.ts": 7553, + "packages/cli/tests/run-composition-nested.test.ts": 20306, + "packages/cli/tests/run-composition.test.ts": 6661, + "packages/cli/tests/run-deadline.test.ts": 8292, + "packages/cli/tests/run-profile.test.ts": 4093, + "packages/cli/tests/run-timeouts.test.ts": 12891, + "packages/cli/tests/secret-detection-cli.test.ts": 18908, + "packages/cli/tests/service-document.test.ts": 5084, + "packages/cli/tests/service-host.test.ts": 4967, + "packages/cli/tests/session-launch-cli.test.ts": 10611, + "packages/cli/tests/stdin-cli.test.ts": 35938, + "packages/cli/tests/stdout-delivery.test.ts": 1493, + "packages/cli/tests/syntax-cli.test.ts": 34967, + "packages/cli/tests/targets-cli.test.ts": 28017, + "packages/cli/tests/test-root-profile.test.ts": 7213, + "packages/cli/tests/test-target.test.ts": 36058, + "packages/cli/tests/testing-activation.test.ts": 4313, + "packages/cli/tests/testing-execution-host.test.ts": 54460, + "packages/cli/tests/upgrade-cli.test.ts": 20416, + "packages/cli/tests/upgrade-command-document.test.ts": 6837, + "packages/cli/tests/upgrade-output.test.ts": 4281, + "packages/cli/tests/value-root.test.ts": 17072, + "packages/cli/tests/verbose-component.test.ts": 4743, + "packages/cli/tests/workflow-agent-sessions.test.ts": 19759, + "packages/cli/tests/workflow-agent.test.ts": 15164, + "packages/cli/tests/workflow-cli.test.ts": 107469, + "packages/cli/tests/workflow-crash.test.ts": 79525, + "packages/cli/tests/workflow-declaration.test.ts": 4297, + "packages/cli/tests/workflow-export-publication.test.ts": 17082, + "packages/cli/tests/workflow-fetch.test.ts": 7813, + "packages/cli/tests/workflow-fork.test.ts": 82603, + "packages/cli/tests/workflow-host.test.ts": 14341, + "packages/cli/tests/workflow-inspection.test.ts": 114514, + "packages/cli/tests/workflow-installation.test.ts": 5789, + "packages/cli/tests/workflow-lifecycle-control.test.ts": 20372, + "packages/cli/tests/workflow-retention.test.ts": 22615, + "packages/cli/tests/workflow-suspension.test.ts": 7433, + "packages/code-review-agent/tests/doctor.test.ts": 1483, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 1506, + "packages/code-review-agent/tests/parse-diff.test.ts": 1487, + "packages/code-review-agent/tests/parse-doctor.test.ts": 3784, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 1447, + "packages/code-review-agent/tests/policy.test.ts": 1472, + "packages/core/tests/agent-api.test.ts": 1504, + "packages/core/tests/agent-components.test.ts": 4337, + "packages/core/tests/agent-function-components.test.ts": 5875, + "packages/core/tests/agent-session-launch.test.ts": 6159, + "packages/core/tests/agent-session-placement.test.ts": 1526, + "packages/core/tests/agent-session-use-loaded-copy.test.ts": 1561, + "packages/core/tests/agent-session-use.test.ts": 1513, + "packages/core/tests/agent-stack.test.ts": 3957, + "packages/core/tests/all.test.ts": 4995, + "packages/core/tests/answer-identity.test.ts": 3439, + "packages/core/tests/answers-component.test.ts": 4532, + "packages/core/tests/answers-expansion-recursion.test.ts": 3632, + "packages/core/tests/capture-errors.test.ts": 3843, + "packages/core/tests/capture-props.test.ts": 3588, + "packages/core/tests/cli-journal.test.ts": 11694, + "packages/core/tests/code-block-component.test.ts": 4993, + "packages/core/tests/compiler-boundary.test.ts": 3665, + "packages/core/tests/component-api.test.ts": 3428, + "packages/core/tests/component-registration.test.ts": 4395, + "packages/core/tests/component-returns.test.ts": 4835, + "packages/core/tests/component-schema-conformance.test.ts": 3712, + "packages/core/tests/config-api.test.ts": 3754, + "packages/core/tests/construct-error-observation.test.ts": 3895, + "packages/core/tests/contextual-cwd.test.ts": 4888, + "packages/core/tests/daemon-integration.test.ts": 4429, + "packages/core/tests/daemon.test.ts": 3463, + "packages/core/tests/declared-markdown-component.test.ts": 5000, + "packages/core/tests/document-output-api.test.ts": 1444, + "packages/core/tests/document-target-execution.test.ts": 6297, + "packages/core/tests/document-targets.test.ts": 3785, + "packages/core/tests/document-validation.test.ts": 5134, + "packages/core/tests/documentation-index.test.ts": 3497, + "packages/core/tests/each.test.ts": 3754, + "packages/core/tests/elicit-component.test.ts": 4298, + "packages/core/tests/ephemeral-service.test.ts": 4165, + "packages/core/tests/eval-bindings.test.ts": 3708, + "packages/core/tests/eval-context.test.ts": 2106, + "packages/core/tests/eval-durable.test.ts": 3720, + "packages/core/tests/eval-error-mode.test.ts": 4028, + "packages/core/tests/eval-interpolate.test.ts": 1459, + "packages/core/tests/eval-middleware.test.ts": 3368, + "packages/core/tests/eval-persist.test.ts": 3852, + "packages/core/tests/eval-return.test.ts": 3733, + "packages/core/tests/eval-scope.test.ts": 3669, + "packages/core/tests/eval-timeout.test.ts": 3755, + "packages/core/tests/eval-transform.test.ts": 3409, + "packages/core/tests/evaluate-component.test.ts": 5494, + "packages/core/tests/evaluate-loaded-copy.test.ts": 3783, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 3875, + "packages/core/tests/evaluation-profile.test.ts": 3560, + "packages/core/tests/exec-timeout.test.ts": 3750, + "packages/core/tests/execute.test.ts": 4289, + "packages/core/tests/execution-protocol.test.ts": 4958, + "packages/core/tests/expand.test.ts": 4424, + "packages/core/tests/expansion-identity.test.ts": 4301, + "packages/core/tests/expansion-metadata.test.ts": 3646, + "packages/core/tests/expression-props.test.ts": 4171, + "packages/core/tests/fail-component.test.ts": 3894, + "packages/core/tests/failure-printing.test.ts": 3859, + "packages/core/tests/fatal-cause.test.ts": 3522, + "packages/core/tests/fetch-component.test.ts": 5018, + "packages/core/tests/file-component.test.ts": 5506, + "packages/core/tests/file-delete-component.test.ts": 3871, + "packages/core/tests/files-fatal.test.ts": 4581, + "packages/core/tests/foreground-exec.test.ts": 4627, + "packages/core/tests/frontmatter.test.ts": 3367, + "packages/core/tests/function-components.test.ts": 4255, + "packages/core/tests/generated-composition.test.ts": 4234, + "packages/core/tests/generated-xmd.test.ts": 5482, + "packages/core/tests/glob-api.test.ts": 1818, + "packages/core/tests/glob-component.test.ts": 4359, + "packages/core/tests/guarded-journal.test.ts": 3714, + "packages/core/tests/has-content.test.ts": 3560, + "packages/core/tests/heal.test.ts": 3600, + "packages/core/tests/if.test.ts": 4203, + "packages/core/tests/inline-root.test.ts": 3775, + "packages/core/tests/invocation-failures.test.ts": 3453, + "packages/core/tests/invocation-identity.test.ts": 4137, + "packages/core/tests/invocation-scope.test.ts": 3835, + "packages/core/tests/journal-source-position.test.ts": 3927, + "packages/core/tests/json-component.test.ts": 3940, + "packages/core/tests/json.test.ts": 3355, + "packages/core/tests/let.test.ts": 3782, + "packages/core/tests/loaded-copy-files.test.ts": 3672, + "packages/core/tests/loop.test.ts": 4503, + "packages/core/tests/named-slots.test.ts": 4522, + "packages/core/tests/output-error-mode.test.ts": 4677, + "packages/core/tests/output-normalize.test.ts": 1484, + "packages/core/tests/output-terminal.test.ts": 1582, + "packages/core/tests/parse-components.test.ts": 3809, + "packages/core/tests/plan-response.test.ts": 1476, + "packages/core/tests/plugin-api.test.ts": 3345, + "packages/core/tests/plugin.test.ts": 3524, + "packages/core/tests/props-binding.test.ts": 3867, + "packages/core/tests/protected-content.test.ts": 3323, + "packages/core/tests/registered-printed-errors.test.ts": 3509, + "packages/core/tests/replay-stream.test.ts": 1445, + "packages/core/tests/retain.test.ts": 3769, + "packages/core/tests/root-composition.test.ts": 3791, + "packages/core/tests/root-props.test.ts": 3881, + "packages/core/tests/root-provider.test.ts": 3844, + "packages/core/tests/sample-component.test.ts": 4527, + "packages/core/tests/scanner.test.ts": 3402, + "packages/core/tests/scope-local.test.ts": 1438, + "packages/core/tests/secret-detection.test.ts": 4477, + "packages/core/tests/secret-files.test.ts": 1909, + "packages/core/tests/secret-rules.test.ts": 2000, + "packages/core/tests/secret-scanner-baseline.test.ts": 1644, + "packages/core/tests/secret-scanner.test.ts": 1821, + "packages/core/tests/source-position.test.ts": 3590, + "packages/core/tests/state-ownership.test.ts": 3629, + "packages/core/tests/streaming-emission.test.ts": 3670, + "packages/core/tests/switch.test.ts": 4235, + "packages/core/tests/syntax-catalog.test.ts": 4262, + "packages/core/tests/syntax-component.test.ts": 4890, + "packages/core/tests/syntax-loaded-copy.test.ts": 3764, + "packages/core/tests/temp-dir.test.ts": 6150, + "packages/core/tests/temp-file-compiler.test.ts": 2119, + "packages/core/tests/text-interpolation.test.ts": 3553, + "packages/core/tests/try-content.test.ts": 3553, + "packages/core/tests/unused-in-diff.test.ts": 3788, + "packages/core/tests/validate.test.ts": 3555, + "packages/core/tests/validation-integration.test.ts": 3660, + "packages/core/tests/workflow-component-bundle.test.ts": 3893, + "packages/durable-streams/tests/context.test.ts": 1692, + "packages/durable-streams/tests/deterministic-id.test.ts": 1744, + "packages/durable-streams/tests/divergence-api.test.ts": 1737, + "packages/durable-streams/tests/divergence.test.ts": 1752, + "packages/durable-streams/tests/durable-each.test.ts": 1745, + "packages/durable-streams/tests/durable-position.test.ts": 1720, + "packages/durable-streams/tests/durable-run.test.ts": 1743, + "packages/durable-streams/tests/ephemeral.test.ts": 1734, + "packages/durable-streams/tests/fail-stop.test.ts": 1754, + "packages/durable-streams/tests/guard-stream.test.ts": 1794, + "packages/durable-streams/tests/live-coordinator.test.ts": 1727, + "packages/durable-streams/tests/parse.test.ts": 1720, + "packages/durable-streams/tests/replay-guard.test.ts": 1818, + "packages/durable-streams/tests/replay-index.test.ts": 1568, + "packages/durable-streams/tests/retained.test.ts": 1549, + "packages/durable-streams/tests/serialize-event.test.ts": 1727, + "packages/durable-streams/tests/smoke.test.ts": 1683, + "packages/durable-streams/tests/structured-concurrency.test.ts": 1863, + "packages/durable-streams/tests/terminal-boundary.test.ts": 1788, + "packages/durable-streams/tests/types.test.ts": 1422, + "packages/git/tests/ambient-authentication.test.ts": 25973, + "packages/git/tests/api-entrypoint.test.ts": 4845, + "packages/git/tests/credential-helper.test.ts": 5733, + "packages/git/tests/git-add-crash.test.ts": 6743, + "packages/git/tests/git-add-durability.test.ts": 25647, + "packages/git/tests/git-add.test.ts": 34009, + "packages/git/tests/git-commit-crash.test.ts": 7034, + "packages/git/tests/git-commit-durability.test.ts": 33023, + "packages/git/tests/git-commit.test.ts": 39374, + "packages/git/tests/git-host-effect.test.ts": 8331, + "packages/git/tests/git-push-crash.test.ts": 9585, + "packages/git/tests/git-push-durability.test.ts": 42379, + "packages/git/tests/git-push.test.ts": 50838, + "packages/git/tests/git-switch-crash.test.ts": 6924, + "packages/git/tests/git-switch-durability.test.ts": 21197, + "packages/git/tests/git-switch.test.ts": 22021, + "packages/git/tests/git.test.ts": 4184, + "packages/git/tests/github-activation.test.ts": 5328, + "packages/git/tests/github-issues.test.ts": 4145, + "packages/git/tests/github-pull-requests.test.ts": 3858, + "packages/git/tests/github-workflow-activation.test.ts": 5653, + "packages/git/tests/issue-markdown.test.ts": 10532, + "packages/git/tests/issue-records.test.ts": 4030, + "packages/git/tests/materialization.test.ts": 4732, + "packages/git/tests/module-partition.test.ts": 4966, + "packages/git/tests/plugin.test.ts": 4448, + "packages/git/tests/provider-neutrality.test.ts": 3264, + "packages/git/tests/public-entrypoint.test.ts": 9495, + "packages/git/tests/pull-request-crash.test.ts": 7874, + "packages/git/tests/pull-request-durability.test.ts": 40608, + "packages/git/tests/pull-request-read.test.ts": 7639, + "packages/git/tests/pull-request-records.test.ts": 4056, + "packages/git/tests/pull-request.test.ts": 72293, + "packages/git/tests/repository-components.test.ts": 11986, + "packages/git/tests/repository-control-plane.test.ts": 10869, + "packages/git/tests/repository-materialization.test.ts": 7959, + "packages/git/tests/repository-replay.test.ts": 15095, + "packages/git/tests/repository-storage.test.ts": 18473, + "packages/git/tests/run-composition-ambient.test.ts": 12538, + "packages/git/tests/run-composition-lazy.test.ts": 5388, + "packages/git/tests/run-composition-managed.test.ts": 14429, + "packages/git/tests/run-composition-remote.test.ts": 15169, + "packages/git/tests/selection-authentication.test.ts": 1740, + "packages/git/tests/worktree-replay.test.ts": 6437, + "packages/runtime/tests/agent-session-coordinator.test.ts": 2058, + "packages/runtime/tests/duration.test.ts": 1501, + "packages/runtime/tests/executable-observer.test.ts": 1777, + "packages/runtime/tests/fetch.test.ts": 2269, + "packages/runtime/tests/fs.test.ts": 1645, + "packages/runtime/tests/host-files.test.ts": 2483, + "packages/runtime/tests/native-launcher.test.ts": 3862, + "packages/runtime/tests/process.test.ts": 1666, + "packages/runtime/tests/service.test.ts": 1749, + "packages/test-agent/tests/acp-server.test.ts": 1627, + "packages/test-agent/tests/behavior-engine.test.ts": 3995, + "packages/test-agent/tests/bridge.test.ts": 3494, + "packages/test-agent/tests/command-lazy.test.ts": 7610, + "packages/test-agent/tests/components.test.ts": 60295, + "packages/test-agent/tests/controller.test.ts": 2721, + "packages/test-agent/tests/cross-package-resolution.test.ts": 5710, + "packages/test-agent/tests/native-launch.test.ts": 29937, + "packages/test-agent/tests/net.test.ts": 1575, + "packages/test-agent/tests/profile.test.ts": 3789, + "packages/test-agent/tests/protocol.test.ts": 2329, + "packages/test-agent/tests/provider.test.ts": 4107, + "packages/test-agent/tests/public-api.test.ts": 4749, + "packages/test-agent/tests/route-slot.test.ts": 1490, + "packages/test-agent/tests/smoke.test.ts": 20543, + "packages/test-agent/tests/template.test.ts": 3826, + "packages/test-agent/tests/worker-lifecycle.test.ts": 13012, + "packages/test-support/tests/journal.test.ts": 1732, + "packages/testing/tests/agent-composition.test.ts": 4034, + "packages/testing/tests/assert-throws.test.ts": 5162, + "packages/testing/tests/assert.test.ts": 1486, + "packages/testing/tests/assertions.test.ts": 5692, + "packages/testing/tests/boundary-contract.test.ts": 4771, + "packages/testing/tests/cli.test.ts": 6526, + "packages/testing/tests/execution-harness.test.ts": 8297, + "packages/testing/tests/replay.test.ts": 5172, + "packages/testing/tests/smoke.test.ts": 5361, + "packages/testing/tests/test-component.test.ts": 5782, + "packages/testing/tests/testing-activation.test.ts": 5472, + "packages/testing/tests/testing-boundary.test.ts": 4399, + "packages/testing/tests/testing-mode.test.ts": 5887, + "packages/testing/tests/use-testing.test.ts": 4923, + "packages/web/tests/assets.test.ts": 1532, + "packages/web/tests/client-logic.test.ts": 1578, + "packages/web/tests/compile.test.ts": 4447, + "packages/web/tests/component.test.ts": 4966, + "packages/web/tests/declaration.test.ts": 4210, + "packages/web/tests/document.test.ts": 4478, + "packages/web/tests/elicitation.test.ts": 4214, + "packages/web/tests/live-form.test.ts": 4139, + "packages/web/tests/markdown.test.ts": 1655, + "packages/web/tests/opener.test.ts": 4102, + "packages/web/tests/page.test.ts": 1479, + "packages/web/tests/responder.test.ts": 4333, + "packages/web/tests/server-lifecycle.test.ts": 4222, + "packages/web/tests/server.test.ts": 4572, + "packages/workflow/tests/generated-agent-component.test.ts": 6318, + "packages/workflow/tests/generated-observations.test.ts": 3953, + "packages/workflow/tests/public-entrypoint.test.ts": 5740, + "packages/workflow/tests/retained-run.test.ts": 4766, + "packages/workflow/tests/service-denial.test.ts": 1762, + "packages/workflow/tests/workflow-agent-checkpoints.test.ts": 5617, + "packages/workflow/tests/workflow-agent-sessions.test.ts": 4708, + "packages/workflow/tests/workflow-bundle.test.ts": 4187, + "packages/workflow/tests/workflow-checkpoint.test.ts": 5776, + "packages/workflow/tests/workflow-definition.test.ts": 3985, + "packages/workflow/tests/workflow-export.test.ts": 7543, + "packages/workflow/tests/workflow-fork-source.test.ts": 4799, + "packages/workflow/tests/workflow-fork.test.ts": 3870, + "packages/workflow/tests/workflow-lifecycle-authority.test.ts": 5713, + "packages/workflow/tests/workflow-lifecycle-control.test.ts": 6316, + "packages/workflow/tests/workflow-lifecycle-inspection.test.ts": 10799, + "packages/workflow/tests/workflow-run-journal.test.ts": 6855, + "packages/workflow/tests/workflow-run-storage.test.ts": 7704, + "packages/workflow/tests/workflow-run.test.ts": 4700, + "packages/workflow/tests/workflow-suspension-answer.test.ts": 5603, + "packages/workflow/tests/workflow-suspension.test.ts": 5290, + "packages/workflow/tests/workspace-crash-recovery.test.ts": 7490, + "packages/workflow/tests/workspace-effect-loaded-copy.test.ts": 4826, + "packages/workflow/tests/workspace-effect-transaction.test.ts": 5492, + "packages/workflow/tests/workspace-effect.test.ts": 5507, + "packages/workflow/tests/workspace-files.test.ts": 11949, + "packages/workflow/tests/workspace-root-restoration.test.ts": 6304, + "packages/workflow/tests/workspace-root.test.ts": 4790, + "packages/workflow/tests/workspace-transaction.test.ts": 4830, + "packages/workflow/tests/xmd-artifact.test.ts": 6443, + "scripts/tests/acpx-vendor.test.ts": 2059, + "scripts/tests/adapter-distribution.test.ts": 4299, + "scripts/tests/adapter-npm-package.test.ts": 31286, + "scripts/tests/adapter-vendor.test.ts": 3839, + "scripts/tests/bootstrap-npm-package.test.ts": 10708, + "scripts/tests/build-npm.test.ts": 38333, + "scripts/tests/build-web-client.test.ts": 28856, + "scripts/tests/bump-version.test.ts": 1605, + "scripts/tests/changed-paths.test.ts": 1492, + "scripts/tests/ci-workflow.test.ts": 4623, + "scripts/tests/cli-npm-bin.test.ts": 235231, + "scripts/tests/cloudflare-dofs-vendor.test.ts": 4168, + "scripts/tests/consumer-cycle.test.ts": 1570, + "scripts/tests/documentation-validation.test.ts": 5983, + "scripts/tests/filesystem-contract-workflow.test.ts": 1481, + "scripts/tests/frozen-entry.test.ts": 8003, + "scripts/tests/jsr-consumer-documentation.test.ts": 17210, + "scripts/tests/main-green.test.ts": 1851, + "scripts/tests/main-health.test.ts": 1622, + "scripts/tests/measure-test-weights.test.ts": 1875, + "scripts/tests/no-module-scoped-registry.test.ts": 2272, + "scripts/tests/no-redundant-test-scope.test.ts": 6327, + "scripts/tests/no-sync-filesystem.test.ts": 6152, + "scripts/tests/no-yield-in-finally.test.ts": 2273, + "scripts/tests/oxlint-policy.test.ts": 11876, + "scripts/tests/packaged-document.test.ts": 1518, + "scripts/tests/prefer-effection-operation.test.ts": 7301, + "scripts/tests/prefer-effection-result.test.ts": 5520, + "scripts/tests/prepared-state.test.ts": 2569, + "scripts/tests/publish-workflow-generator.test.ts": 5856, + "scripts/tests/publish-workflow-membership.test.ts": 1621, + "scripts/tests/publishable-membership-agreement.test.ts": 3824, + "scripts/tests/readme-targets.test.ts": 18157, + "scripts/tests/release-targets.test.ts": 1554, + "scripts/tests/review-infrastructure.test.ts": 5782, + "scripts/tests/runtime-exclusions.test.ts": 1928, + "scripts/tests/runtime-tests.test.ts": 1618, + "scripts/tests/scope-bound-event-registration.test.ts": 6098, + "scripts/tests/shard-execution.test.ts": 11071, + "scripts/tests/staged-write.test.ts": 1517, + "scripts/tests/test-file-discovery.test.ts": 1744, + "scripts/tests/test-shards.test.ts": 1520, + "scripts/tests/test-weights.test.ts": 1760, + "scripts/tests/tracked.test.ts": 1487, + "scripts/tests/verify-adapter.test.ts": 7650, + "scripts/tests/verify-clean.test.ts": 1672, + "scripts/tests/verify-coordinator.test.ts": 1836, + "scripts/tests/version-lockstep.test.ts": 1652, + "scripts/tests/web-client-module.test.ts": 1508, + "scripts/tests/workspace.test.ts": 1468 }, "node": { - "packages/acp/tests/acceptance.test.ts": 2147, + "packages/acp/tests/acceptance.test.ts": 2046, "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4862, - "packages/acp/tests/acpx-materialization.test.ts": 7066, - "packages/acp/tests/acpx-transient-env.test.ts": 831, - "packages/acp/tests/adapter-materialization.test.ts": 75480, - "packages/acp/tests/adapter-protocol.test.ts": 56405, - "packages/acp/tests/codex-surfaces.test.ts": 655, - "packages/acp/tests/native-launch.test.ts": 2201, - "packages/acp/tests/permission-bridge.test.ts": 1229, - "packages/acp/tests/provider.test.ts": 2181, - "packages/acp/tests/serial-queue.test.ts": 492, - "packages/acp/tests/session-key.test.ts": 531, - "packages/acp/tests/terminal-screen.test.ts": 624, - "packages/cli/tests/agent-adapters.test.ts": 2472, - "packages/cli/tests/agent-cli.test.ts": 43764, - "packages/cli/tests/agent-config.test.ts": 500, - "packages/cli/tests/agent-options-cli.test.ts": 16751, - "packages/cli/tests/agent-options.test.ts": 522, - "packages/cli/tests/agent-session-coordinator.test.ts": 1411, - "packages/cli/tests/cli-help.test.ts": 41839, - "packages/cli/tests/command.test.ts": 15202, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 4371, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 172095, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 3658, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 10009, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 6132, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 18184, - "packages/cli/tests/evaluate-component.test.ts": 15576, - "packages/cli/tests/fetch-cli.test.ts": 5042, - "packages/cli/tests/file-stream.test.ts": 553, - "packages/cli/tests/inline-cli.test.ts": 69253, - "packages/cli/tests/launch-timeout.test.ts": 20556, - "packages/cli/tests/packaged-document.test.ts": 1703, - "packages/cli/tests/plan-args.test.ts": 530, - "packages/cli/tests/plan-cli.test.ts": 123356, - "packages/cli/tests/plan-command-document.test.ts": 8342, - "packages/cli/tests/plan-component.test.ts": 11574, - "packages/cli/tests/plan-host-acts.test.ts": 2493, - "packages/cli/tests/plan.test.ts": 16183, - "packages/cli/tests/plugin-cli.test.ts": 83902, - "packages/cli/tests/plugin-host.test.ts": 3312, - "packages/cli/tests/plugin-modules.test.ts": 503, - "packages/cli/tests/plugin-selection.test.ts": 501, - "packages/cli/tests/process-retention.test.ts": 4939, - "packages/cli/tests/props-cli.test.ts": 64277, - "packages/cli/tests/props-schema.test.ts": 1366, - "packages/cli/tests/props-sources.test.ts": 725, - "packages/cli/tests/repl-boundaries.test.ts": 2599, - "packages/cli/tests/repl-composition.test.ts": 757, - "packages/cli/tests/repl-execution.test.ts": 2984, - "packages/cli/tests/repl-journey.test.ts": 11219, - "packages/cli/tests/repl-model.test.ts": 2751, - "packages/cli/tests/repl-route.test.ts": 2323, - "packages/cli/tests/repl-terminal.test.ts": 1299, - "packages/cli/tests/run-composition.test.ts": 4155, - "packages/cli/tests/run-deadline.test.ts": 3703, - "packages/cli/tests/run-profile.test.ts": 1248, - "packages/cli/tests/run-timeouts.test.ts": 20443, - "packages/cli/tests/secret-detection-cli.test.ts": 38329, - "packages/cli/tests/service-document.test.ts": 2608, - "packages/cli/tests/service-host.test.ts": 2376, - "packages/cli/tests/session-launch-cli.test.ts": 11240, - "packages/cli/tests/stdin-cli.test.ts": 64256, - "packages/cli/tests/stdout-delivery.test.ts": 505, - "packages/cli/tests/syntax-cli.test.ts": 63780, - "packages/cli/tests/targets-cli.test.ts": 51410, - "packages/cli/tests/test-root-profile.test.ts": 7052, - "packages/cli/tests/test-target.test.ts": 73779, - "packages/cli/tests/testing-activation.test.ts": 1493, - "packages/cli/tests/testing-execution-host.test.ts": 91221, - "packages/cli/tests/upgrade-cli.test.ts": 46915, - "packages/cli/tests/upgrade-command-document.test.ts": 5542, - "packages/cli/tests/upgrade-output.test.ts": 1974, - "packages/cli/tests/value-root.test.ts": 32957, - "packages/cli/tests/verbose-component.test.ts": 1951, - "packages/cli/tests/workflow-declaration.test.ts": 1506, - "packages/cli/tests/workflow-host.test.ts": 11110, - "packages/code-review-agent/tests/doctor.test.ts": 510, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 528, - "packages/code-review-agent/tests/parse-diff.test.ts": 508, - "packages/code-review-agent/tests/parse-doctor.test.ts": 1178, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 491, - "packages/code-review-agent/tests/policy.test.ts": 502, - "packages/core/tests/agent-api.test.ts": 508, - "packages/core/tests/agent-components.test.ts": 2045, - "packages/core/tests/agent-function-components.test.ts": 4256, - "packages/core/tests/agent-session-launch.test.ts": 4597, - "packages/core/tests/agent-session-placement.test.ts": 508, - "packages/core/tests/agent-session-use.test.ts": 486, - "packages/core/tests/agent-stack.test.ts": 1520, - "packages/core/tests/all.test.ts": 2954, - "packages/core/tests/answer-identity.test.ts": 572, - "packages/core/tests/answers-component.test.ts": 2393, - "packages/core/tests/answers-expansion-recursion.test.ts": 969, - "packages/core/tests/capture-errors.test.ts": 1255, - "packages/core/tests/capture-props.test.ts": 1006, - "packages/core/tests/cli-journal.test.ts": 22366, - "packages/core/tests/code-block-component.test.ts": 3204, - "packages/core/tests/compiler-boundary.test.ts": 1148, - "packages/core/tests/component-api.test.ts": 540, - "packages/core/tests/component-registration.test.ts": 2102, - "packages/core/tests/component-returns.test.ts": 2887, - "packages/core/tests/component-schema-conformance.test.ts": 1154, - "packages/core/tests/config-api.test.ts": 1278, - "packages/core/tests/construct-error-observation.test.ts": 1400, - "packages/core/tests/contextual-cwd.test.ts": 2451, - "packages/core/tests/daemon-integration.test.ts": 1919, - "packages/core/tests/daemon.test.ts": 576, - "packages/core/tests/declared-markdown-component.test.ts": 3179, - "packages/core/tests/document-output-api.test.ts": 512, - "packages/core/tests/document-target-execution.test.ts": 4694, - "packages/core/tests/document-targets.test.ts": 1195, - "packages/core/tests/document-validation.test.ts": 3029, - "packages/core/tests/documentation-index.test.ts": 839, - "packages/core/tests/each.test.ts": 1269, - "packages/core/tests/elicit-component.test.ts": 2044, - "packages/core/tests/ephemeral-service.test.ts": 1842, - "packages/core/tests/eval-bindings.test.ts": 1279, - "packages/core/tests/eval-context.test.ts": 599, - "packages/core/tests/eval-durable.test.ts": 1328, - "packages/core/tests/eval-error-mode.test.ts": 1658, - "packages/core/tests/eval-interpolate.test.ts": 507, - "packages/core/tests/eval-middleware.test.ts": 598, - "packages/core/tests/eval-persist.test.ts": 1380, - "packages/core/tests/eval-return.test.ts": 1277, - "packages/core/tests/eval-scope.test.ts": 1206, - "packages/core/tests/eval-timeout.test.ts": 1268, - "packages/core/tests/eval-transform.test.ts": 588, - "packages/core/tests/evaluate-component.test.ts": 3665, - "packages/core/tests/evaluate-loaded-copy.test.ts": 1380, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 1419, - "packages/core/tests/evaluation-profile.test.ts": 887, - "packages/core/tests/exec-timeout.test.ts": 1342, - "packages/core/tests/execute.test.ts": 1998, - "packages/core/tests/execution-protocol.test.ts": 2813, - "packages/core/tests/expand.test.ts": 1980, - "packages/core/tests/expansion-identity.test.ts": 2012, - "packages/core/tests/expansion-metadata.test.ts": 1020, - "packages/core/tests/expression-props.test.ts": 1880, - "packages/core/tests/fail-component.test.ts": 1667, - "packages/core/tests/failure-printing.test.ts": 1463, - "packages/core/tests/fatal-cause.test.ts": 876, - "packages/core/tests/fetch-component.test.ts": 2924, - "packages/core/tests/file-component.test.ts": 3417, - "packages/core/tests/file-delete-component.test.ts": 1494, - "packages/core/tests/files-fatal.test.ts": 2511, - "packages/core/tests/foreground-exec.test.ts": 2337, - "packages/core/tests/frontmatter.test.ts": 558, - "packages/core/tests/function-components.test.ts": 1988, - "packages/core/tests/generated-composition.test.ts": 2075, - "packages/core/tests/generated-xmd.test.ts": 3603, - "packages/core/tests/glob-api.test.ts": 593, - "packages/core/tests/glob-component.test.ts": 2069, - "packages/core/tests/guarded-journal.test.ts": 1356, - "packages/core/tests/has-content.test.ts": 931, - "packages/core/tests/heal.test.ts": 941, - "packages/core/tests/if.test.ts": 1832, - "packages/core/tests/inline-root.test.ts": 1366, - "packages/core/tests/invocation-failures.test.ts": 600, - "packages/core/tests/invocation-identity.test.ts": 1791, - "packages/core/tests/invocation-scope.test.ts": 1201, - "packages/core/tests/journal-source-position.test.ts": 1451, - "packages/core/tests/json-component.test.ts": 1587, - "packages/core/tests/json.test.ts": 497, - "packages/core/tests/let.test.ts": 1332, - "packages/core/tests/loop.test.ts": 2313, - "packages/core/tests/named-slots.test.ts": 2317, - "packages/core/tests/output-error-mode.test.ts": 2657, - "packages/core/tests/output-normalize.test.ts": 507, - "packages/core/tests/output-terminal.test.ts": 694, - "packages/core/tests/parse-components.test.ts": 1454, - "packages/core/tests/plan-response.test.ts": 594, - "packages/core/tests/plugin-api.test.ts": 529, - "packages/core/tests/plugin.test.ts": 1006, - "packages/core/tests/props-binding.test.ts": 1467, - "packages/core/tests/protected-content.test.ts": 558, - "packages/core/tests/registered-printed-errors.test.ts": 863, - "packages/core/tests/replay-stream.test.ts": 506, - "packages/core/tests/retain.test.ts": 1137, - "packages/core/tests/root-composition.test.ts": 1407, - "packages/core/tests/root-props.test.ts": 1480, - "packages/core/tests/root-provider.test.ts": 1350, - "packages/core/tests/sample-component.test.ts": 2358, - "packages/core/tests/scanner.test.ts": 578, - "packages/core/tests/scope-local.test.ts": 505, - "packages/core/tests/secret-detection.test.ts": 2130, - "packages/core/tests/secret-files.test.ts": 774, - "packages/core/tests/secret-rules.test.ts": 860, - "packages/core/tests/secret-scanner-baseline.test.ts": 755, - "packages/core/tests/secret-scanner.test.ts": 702, - "packages/core/tests/source-position.test.ts": 1166, - "packages/core/tests/state-ownership.test.ts": 1254, - "packages/core/tests/streaming-emission.test.ts": 1175, - "packages/core/tests/switch.test.ts": 1881, - "packages/core/tests/syntax-catalog.test.ts": 1843, - "packages/core/tests/syntax-component.test.ts": 2691, - "packages/core/tests/temp-dir.test.ts": 3741, - "packages/core/tests/temp-file-compiler.test.ts": 551, - "packages/core/tests/text-interpolation.test.ts": 912, - "packages/core/tests/try-content.test.ts": 939, - "packages/core/tests/unused-in-diff.test.ts": 1354, - "packages/core/tests/validate.test.ts": 818, - "packages/core/tests/validation-integration.test.ts": 1192, - "packages/core/tests/workflow-component-bundle.test.ts": 1577, - "packages/durable-streams/tests/context.test.ts": 516, - "packages/durable-streams/tests/deterministic-id.test.ts": 544, - "packages/durable-streams/tests/divergence-api.test.ts": 537, - "packages/durable-streams/tests/divergence.test.ts": 576, - "packages/durable-streams/tests/durable-each.test.ts": 578, - "packages/durable-streams/tests/durable-position.test.ts": 549, - "packages/durable-streams/tests/durable-run.test.ts": 555, - "packages/durable-streams/tests/ephemeral.test.ts": 559, - "packages/durable-streams/tests/fail-stop.test.ts": 636, - "packages/durable-streams/tests/guard-stream.test.ts": 628, - "packages/durable-streams/tests/live-coordinator.test.ts": 543, - "packages/durable-streams/tests/parse.test.ts": 573, - "packages/durable-streams/tests/replay-guard.test.ts": 605, - "packages/durable-streams/tests/replay-index.test.ts": 543, - "packages/durable-streams/tests/retained.test.ts": 515, - "packages/durable-streams/tests/serialize-event.test.ts": 545, + "packages/acp/tests/acpx-materialization.test.ts": 7053, + "packages/acp/tests/acpx-transient-env.test.ts": 797, + "packages/acp/tests/adapter-materialization.test.ts": 72478, + "packages/acp/tests/adapter-protocol.test.ts": 53071, + "packages/acp/tests/codex-surfaces.test.ts": 651, + "packages/acp/tests/native-launch.test.ts": 2114, + "packages/acp/tests/permission-bridge.test.ts": 1198, + "packages/acp/tests/provider.test.ts": 2070, + "packages/acp/tests/serial-queue.test.ts": 495, + "packages/acp/tests/session-key.test.ts": 528, + "packages/acp/tests/terminal-screen.test.ts": 587, + "packages/cli/tests/agent-adapters.test.ts": 2345, + "packages/cli/tests/agent-cli.test.ts": 41155, + "packages/cli/tests/agent-config.test.ts": 476, + "packages/cli/tests/agent-options-cli.test.ts": 15462, + "packages/cli/tests/agent-options.test.ts": 485, + "packages/cli/tests/agent-session-coordinator.test.ts": 1338, + "packages/cli/tests/cli-help.test.ts": 39037, + "packages/cli/tests/command.test.ts": 14308, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 4025, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 166249, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 3423, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 9374, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 5704, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 17252, + "packages/cli/tests/evaluate-component.test.ts": 14552, + "packages/cli/tests/fetch-cli.test.ts": 4700, + "packages/cli/tests/file-stream.test.ts": 531, + "packages/cli/tests/inline-cli.test.ts": 64136, + "packages/cli/tests/launch-timeout.test.ts": 20549, + "packages/cli/tests/packaged-document.test.ts": 1523, + "packages/cli/tests/plan-args.test.ts": 504, + "packages/cli/tests/plan-cli.test.ts": 113225, + "packages/cli/tests/plan-command-document.test.ts": 7456, + "packages/cli/tests/plan-component.test.ts": 10180, + "packages/cli/tests/plan-host-acts.test.ts": 2225, + "packages/cli/tests/plan.test.ts": 14740, + "packages/cli/tests/plugin-cli.test.ts": 77902, + "packages/cli/tests/plugin-host.test.ts": 3066, + "packages/cli/tests/plugin-modules.test.ts": 490, + "packages/cli/tests/plugin-selection.test.ts": 507, + "packages/cli/tests/process-retention.test.ts": 4662, + "packages/cli/tests/props-cli.test.ts": 60420, + "packages/cli/tests/props-schema.test.ts": 1304, + "packages/cli/tests/props-sources.test.ts": 665, + "packages/cli/tests/repl-boundaries.test.ts": 2400, + "packages/cli/tests/repl-composition.test.ts": 707, + "packages/cli/tests/repl-execution.test.ts": 2771, + "packages/cli/tests/repl-journey.test.ts": 11026, + "packages/cli/tests/repl-model.test.ts": 2555, + "packages/cli/tests/repl-route.test.ts": 2148, + "packages/cli/tests/repl-terminal.test.ts": 1251, + "packages/cli/tests/run-composition.test.ts": 3845, + "packages/cli/tests/run-deadline.test.ts": 3575, + "packages/cli/tests/run-profile.test.ts": 1203, + "packages/cli/tests/run-timeouts.test.ts": 19546, + "packages/cli/tests/secret-detection-cli.test.ts": 35993, + "packages/cli/tests/service-document.test.ts": 2540, + "packages/cli/tests/service-host.test.ts": 2331, + "packages/cli/tests/session-launch-cli.test.ts": 10504, + "packages/cli/tests/stdin-cli.test.ts": 60273, + "packages/cli/tests/stdout-delivery.test.ts": 481, + "packages/cli/tests/syntax-cli.test.ts": 58954, + "packages/cli/tests/targets-cli.test.ts": 48955, + "packages/cli/tests/test-root-profile.test.ts": 6726, + "packages/cli/tests/test-target.test.ts": 70319, + "packages/cli/tests/testing-activation.test.ts": 1405, + "packages/cli/tests/testing-execution-host.test.ts": 86424, + "packages/cli/tests/upgrade-cli.test.ts": 44503, + "packages/cli/tests/upgrade-command-document.test.ts": 5111, + "packages/cli/tests/upgrade-output.test.ts": 1768, + "packages/cli/tests/value-root.test.ts": 29628, + "packages/cli/tests/verbose-component.test.ts": 1850, + "packages/cli/tests/workflow-declaration.test.ts": 1422, + "packages/cli/tests/workflow-host.test.ts": 10303, + "packages/code-review-agent/tests/doctor.test.ts": 474, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 509, + "packages/code-review-agent/tests/parse-diff.test.ts": 482, + "packages/code-review-agent/tests/parse-doctor.test.ts": 1127, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 473, + "packages/code-review-agent/tests/policy.test.ts": 491, + "packages/core/tests/agent-api.test.ts": 486, + "packages/core/tests/agent-components.test.ts": 1915, + "packages/core/tests/agent-function-components.test.ts": 3966, + "packages/core/tests/agent-session-launch.test.ts": 3938, + "packages/core/tests/agent-session-placement.test.ts": 476, + "packages/core/tests/agent-session-use.test.ts": 467, + "packages/core/tests/agent-stack.test.ts": 1449, + "packages/core/tests/all.test.ts": 2788, + "packages/core/tests/answer-identity.test.ts": 546, + "packages/core/tests/answers-component.test.ts": 2208, + "packages/core/tests/answers-expansion-recursion.test.ts": 927, + "packages/core/tests/capture-errors.test.ts": 1205, + "packages/core/tests/capture-props.test.ts": 953, + "packages/core/tests/cli-journal.test.ts": 20838, + "packages/core/tests/code-block-component.test.ts": 2893, + "packages/core/tests/compiler-boundary.test.ts": 1116, + "packages/core/tests/component-api.test.ts": 545, + "packages/core/tests/component-registration.test.ts": 1968, + "packages/core/tests/component-returns.test.ts": 2651, + "packages/core/tests/component-schema-conformance.test.ts": 1079, + "packages/core/tests/config-api.test.ts": 1220, + "packages/core/tests/construct-error-observation.test.ts": 1278, + "packages/core/tests/contextual-cwd.test.ts": 2405, + "packages/core/tests/daemon-integration.test.ts": 1844, + "packages/core/tests/daemon.test.ts": 548, + "packages/core/tests/declared-markdown-component.test.ts": 2971, + "packages/core/tests/document-output-api.test.ts": 496, + "packages/core/tests/document-target-execution.test.ts": 4299, + "packages/core/tests/document-targets.test.ts": 1149, + "packages/core/tests/document-validation.test.ts": 2819, + "packages/core/tests/documentation-index.test.ts": 820, + "packages/core/tests/each.test.ts": 1222, + "packages/core/tests/elicit-component.test.ts": 1886, + "packages/core/tests/ephemeral-service.test.ts": 1715, + "packages/core/tests/eval-bindings.test.ts": 1176, + "packages/core/tests/eval-context.test.ts": 573, + "packages/core/tests/eval-durable.test.ts": 1250, + "packages/core/tests/eval-error-mode.test.ts": 1575, + "packages/core/tests/eval-interpolate.test.ts": 502, + "packages/core/tests/eval-middleware.test.ts": 579, + "packages/core/tests/eval-persist.test.ts": 1346, + "packages/core/tests/eval-return.test.ts": 1233, + "packages/core/tests/eval-scope.test.ts": 1116, + "packages/core/tests/eval-timeout.test.ts": 1214, + "packages/core/tests/eval-transform.test.ts": 567, + "packages/core/tests/evaluate-component.test.ts": 3324, + "packages/core/tests/evaluate-loaded-copy.test.ts": 1291, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 1349, + "packages/core/tests/evaluation-profile.test.ts": 855, + "packages/core/tests/exec-timeout.test.ts": 1271, + "packages/core/tests/execute.test.ts": 1850, + "packages/core/tests/execution-protocol.test.ts": 2698, + "packages/core/tests/expand.test.ts": 1868, + "packages/core/tests/expansion-identity.test.ts": 1911, + "packages/core/tests/expansion-metadata.test.ts": 954, + "packages/core/tests/expression-props.test.ts": 1780, + "packages/core/tests/fail-component.test.ts": 1568, + "packages/core/tests/failure-printing.test.ts": 1390, + "packages/core/tests/fatal-cause.test.ts": 879, + "packages/core/tests/fetch-component.test.ts": 2722, + "packages/core/tests/file-component.test.ts": 3237, + "packages/core/tests/file-delete-component.test.ts": 1407, + "packages/core/tests/files-fatal.test.ts": 2279, + "packages/core/tests/foreground-exec.test.ts": 2227, + "packages/core/tests/frontmatter.test.ts": 532, + "packages/core/tests/function-components.test.ts": 1924, + "packages/core/tests/generated-composition.test.ts": 1905, + "packages/core/tests/generated-xmd.test.ts": 3319, + "packages/core/tests/glob-api.test.ts": 586, + "packages/core/tests/glob-component.test.ts": 1962, + "packages/core/tests/guarded-journal.test.ts": 1290, + "packages/core/tests/has-content.test.ts": 902, + "packages/core/tests/heal.test.ts": 911, + "packages/core/tests/if.test.ts": 1789, + "packages/core/tests/inline-root.test.ts": 1305, + "packages/core/tests/invocation-failures.test.ts": 587, + "packages/core/tests/invocation-identity.test.ts": 1708, + "packages/core/tests/invocation-scope.test.ts": 1149, + "packages/core/tests/journal-source-position.test.ts": 1386, + "packages/core/tests/json-component.test.ts": 1460, + "packages/core/tests/json.test.ts": 488, + "packages/core/tests/let.test.ts": 1250, + "packages/core/tests/loop.test.ts": 2136, + "packages/core/tests/named-slots.test.ts": 2180, + "packages/core/tests/output-error-mode.test.ts": 2395, + "packages/core/tests/output-normalize.test.ts": 500, + "packages/core/tests/output-terminal.test.ts": 687, + "packages/core/tests/parse-components.test.ts": 1357, + "packages/core/tests/plan-response.test.ts": 583, + "packages/core/tests/plugin-api.test.ts": 523, + "packages/core/tests/plugin.test.ts": 980, + "packages/core/tests/props-binding.test.ts": 1417, + "packages/core/tests/protected-content.test.ts": 527, + "packages/core/tests/registered-printed-errors.test.ts": 881, + "packages/core/tests/replay-stream.test.ts": 487, + "packages/core/tests/retain.test.ts": 1100, + "packages/core/tests/root-composition.test.ts": 1310, + "packages/core/tests/root-props.test.ts": 1395, + "packages/core/tests/root-provider.test.ts": 1293, + "packages/core/tests/sample-component.test.ts": 2221, + "packages/core/tests/scanner.test.ts": 567, + "packages/core/tests/scope-local.test.ts": 489, + "packages/core/tests/secret-detection.test.ts": 2012, + "packages/core/tests/secret-files.test.ts": 741, + "packages/core/tests/secret-rules.test.ts": 808, + "packages/core/tests/secret-scanner-baseline.test.ts": 741, + "packages/core/tests/secret-scanner.test.ts": 701, + "packages/core/tests/source-position.test.ts": 1112, + "packages/core/tests/state-ownership.test.ts": 1191, + "packages/core/tests/streaming-emission.test.ts": 1134, + "packages/core/tests/switch.test.ts": 1800, + "packages/core/tests/syntax-catalog.test.ts": 1768, + "packages/core/tests/syntax-component.test.ts": 2531, + "packages/core/tests/temp-dir.test.ts": 3664, + "packages/core/tests/temp-file-compiler.test.ts": 537, + "packages/core/tests/text-interpolation.test.ts": 867, + "packages/core/tests/try-content.test.ts": 902, + "packages/core/tests/unused-in-diff.test.ts": 1304, + "packages/core/tests/validate.test.ts": 795, + "packages/core/tests/validation-integration.test.ts": 1208, + "packages/core/tests/workflow-component-bundle.test.ts": 1471, + "packages/durable-streams/tests/context.test.ts": 499, + "packages/durable-streams/tests/deterministic-id.test.ts": 546, + "packages/durable-streams/tests/divergence-api.test.ts": 529, + "packages/durable-streams/tests/divergence.test.ts": 550, + "packages/durable-streams/tests/durable-each.test.ts": 580, + "packages/durable-streams/tests/durable-position.test.ts": 543, + "packages/durable-streams/tests/durable-run.test.ts": 552, + "packages/durable-streams/tests/ephemeral.test.ts": 532, + "packages/durable-streams/tests/fail-stop.test.ts": 602, + "packages/durable-streams/tests/guard-stream.test.ts": 662, + "packages/durable-streams/tests/live-coordinator.test.ts": 533, + "packages/durable-streams/tests/parse.test.ts": 569, + "packages/durable-streams/tests/replay-guard.test.ts": 575, + "packages/durable-streams/tests/replay-index.test.ts": 531, + "packages/durable-streams/tests/retained.test.ts": 530, + "packages/durable-streams/tests/serialize-event.test.ts": 521, "packages/durable-streams/tests/smoke.test.ts": 521, - "packages/durable-streams/tests/structured-concurrency.test.ts": 621, - "packages/durable-streams/tests/terminal-boundary.test.ts": 574, - "packages/durable-streams/tests/types.test.ts": 491, - "packages/git/tests/api-entrypoint.test.ts": 1319, - "packages/git/tests/git-host-effect.test.ts": 7549, - "packages/git/tests/git.test.ts": 1318, - "packages/git/tests/github-activation.test.ts": 1688, - "packages/git/tests/github-issues.test.ts": 1216, - "packages/git/tests/github-pull-requests.test.ts": 604, - "packages/git/tests/issue-markdown.test.ts": 10038, - "packages/git/tests/issue-records.test.ts": 1202, - "packages/git/tests/module-partition.test.ts": 3280, - "packages/git/tests/plugin.test.ts": 1723, - "packages/git/tests/provider-neutrality.test.ts": 2318, - "packages/git/tests/pull-request-records.test.ts": 1248, - "packages/git/tests/run-composition-lazy.test.ts": 2035, - "packages/git/tests/selection-authentication.test.ts": 489, - "packages/runtime/tests/duration.test.ts": 486, - "packages/runtime/tests/fetch.test.ts": 1123, - "packages/runtime/tests/fs.test.ts": 555, - "packages/runtime/tests/host-files.test.ts": 1291, - "packages/runtime/tests/native-launcher.test.ts": 2851, - "packages/runtime/tests/process.test.ts": 548, - "packages/runtime/tests/service.test.ts": 523, - "packages/test-agent/tests/acp-server.test.ts": 667, - "packages/test-agent/tests/behavior-engine.test.ts": 1586, - "packages/test-agent/tests/bridge.test.ts": 528, - "packages/test-agent/tests/command-lazy.test.ts": 6610, - "packages/test-agent/tests/components.test.ts": 107656, - "packages/test-agent/tests/controller.test.ts": 824, - "packages/test-agent/tests/cross-package-resolution.test.ts": 3031, - "packages/test-agent/tests/native-launch.test.ts": 55277, - "packages/test-agent/tests/net.test.ts": 602, - "packages/test-agent/tests/profile.test.ts": 1191, - "packages/test-agent/tests/protocol.test.ts": 614, - "packages/test-agent/tests/provider.test.ts": 1373, - "packages/test-agent/tests/public-api.test.ts": 1532, - "packages/test-agent/tests/route-slot.test.ts": 521, - "packages/test-agent/tests/smoke.test.ts": 29089, - "packages/test-agent/tests/template.test.ts": 1187, - "packages/test-agent/tests/worker-lifecycle.test.ts": 24095, - "packages/test-support/tests/journal.test.ts": 526, - "packages/testing/tests/agent-composition.test.ts": 1538, - "packages/testing/tests/assert-throws.test.ts": 3371, - "packages/testing/tests/assert.test.ts": 527, - "packages/testing/tests/assertions.test.ts": 3893, - "packages/testing/tests/boundary-contract.test.ts": 2577, - "packages/testing/tests/cli.test.ts": 11249, - "packages/testing/tests/execution-harness.test.ts": 7889, - "packages/testing/tests/replay.test.ts": 3161, - "packages/testing/tests/smoke.test.ts": 3257, - "packages/testing/tests/test-component.test.ts": 3874, - "packages/testing/tests/testing-activation.test.ts": 3441, - "packages/testing/tests/testing-boundary.test.ts": 2024, - "packages/testing/tests/testing-mode.test.ts": 4100, - "packages/testing/tests/use-testing.test.ts": 2929, - "packages/web/tests/assets.test.ts": 502, - "packages/web/tests/client-logic.test.ts": 545, - "packages/web/tests/compile.test.ts": 2042, - "packages/web/tests/component.test.ts": 2621, - "packages/web/tests/declaration.test.ts": 1760, - "packages/web/tests/document.test.ts": 1859, - "packages/web/tests/elicitation.test.ts": 1631, - "packages/web/tests/live-form.test.ts": 1546, - "packages/web/tests/markdown.test.ts": 721, - "packages/web/tests/opener.test.ts": 1558, - "packages/web/tests/page.test.ts": 504, - "packages/web/tests/responder.test.ts": 1867, - "packages/web/tests/server-lifecycle.test.ts": 1673, - "packages/web/tests/server.test.ts": 2131, - "packages/workflow/tests/generated-observations.test.ts": 1601, - "packages/workflow/tests/retained-run.test.ts": 2288, - "packages/workflow/tests/service-denial.test.ts": 542, - "packages/workflow/tests/workflow-bundle.test.ts": 1707, - "packages/workflow/tests/workflow-definition.test.ts": 1386, - "packages/workflow/tests/workflow-fork.test.ts": 1225, - "packages/workflow/tests/workflow-run.test.ts": 2209, - "packages/workflow/tests/workspace-effect.test.ts": 3116, - "packages/workflow/tests/xmd-artifact.test.ts": 3692, - "scripts/tests/adapter-vendor.test.ts": 744, - "scripts/tests/bootstrap-npm-package.test.ts": 8423, - "scripts/tests/bump-version.test.ts": 619, - "scripts/tests/changed-paths.test.ts": 526, - "scripts/tests/ci-workflow.test.ts": 3623, - "scripts/tests/consumer-cycle.test.ts": 683, - "scripts/tests/filesystem-contract-workflow.test.ts": 593, - "scripts/tests/main-green.test.ts": 779, - "scripts/tests/main-health.test.ts": 622, - "scripts/tests/no-module-scoped-registry.test.ts": 1340, - "scripts/tests/no-redundant-test-scope.test.ts": 5431, - "scripts/tests/no-sync-filesystem.test.ts": 5783, - "scripts/tests/no-yield-in-finally.test.ts": 1341, - "scripts/tests/oxlint-policy.test.ts": 11094, - "scripts/tests/packaged-document.test.ts": 601, - "scripts/tests/prefer-effection-operation.test.ts": 6511, - "scripts/tests/prefer-effection-result.test.ts": 4678, - "scripts/tests/publish-workflow-membership.test.ts": 692, - "scripts/tests/review-infrastructure.test.ts": 3415, - "scripts/tests/runtime-exclusions.test.ts": 1095, - "scripts/tests/runtime-tests.test.ts": 589, - "scripts/tests/scope-bound-event-registration.test.ts": 5516, - "scripts/tests/staged-write.test.ts": 585, - "scripts/tests/test-file-discovery.test.ts": 866, - "scripts/tests/test-shards.test.ts": 559, - "scripts/tests/test-weights.test.ts": 749, - "scripts/tests/tracked.test.ts": 534, - "scripts/tests/verify-coordinator.test.ts": 769, - "scripts/tests/version-lockstep.test.ts": 719, - "scripts/tests/web-client-module.test.ts": 536, - "scripts/tests/workspace.test.ts": 505 + "packages/durable-streams/tests/structured-concurrency.test.ts": 577, + "packages/durable-streams/tests/terminal-boundary.test.ts": 566, + "packages/durable-streams/tests/types.test.ts": 478, + "packages/git/tests/api-entrypoint.test.ts": 1273, + "packages/git/tests/git-host-effect.test.ts": 6666, + "packages/git/tests/git.test.ts": 1278, + "packages/git/tests/github-activation.test.ts": 1607, + "packages/git/tests/github-issues.test.ts": 1172, + "packages/git/tests/github-pull-requests.test.ts": 590, + "packages/git/tests/issue-markdown.test.ts": 9270, + "packages/git/tests/issue-records.test.ts": 1149, + "packages/git/tests/module-partition.test.ts": 2938, + "packages/git/tests/plugin.test.ts": 1664, + "packages/git/tests/provider-neutrality.test.ts": 2174, + "packages/git/tests/pull-request-records.test.ts": 1254, + "packages/git/tests/run-composition-lazy.test.ts": 1887, + "packages/git/tests/selection-authentication.test.ts": 492, + "packages/runtime/tests/duration.test.ts": 489, + "packages/runtime/tests/fetch.test.ts": 1100, + "packages/runtime/tests/fs.test.ts": 547, + "packages/runtime/tests/host-files.test.ts": 1249, + "packages/runtime/tests/native-launcher.test.ts": 2854, + "packages/runtime/tests/process.test.ts": 528, + "packages/runtime/tests/service.test.ts": 518, + "packages/test-agent/tests/acp-server.test.ts": 678, + "packages/test-agent/tests/behavior-engine.test.ts": 1531, + "packages/test-agent/tests/bridge.test.ts": 497, + "packages/test-agent/tests/command-lazy.test.ts": 6266, + "packages/test-agent/tests/components.test.ts": 102774, + "packages/test-agent/tests/controller.test.ts": 761, + "packages/test-agent/tests/cross-package-resolution.test.ts": 2749, + "packages/test-agent/tests/native-launch.test.ts": 52135, + "packages/test-agent/tests/net.test.ts": 582, + "packages/test-agent/tests/profile.test.ts": 1151, + "packages/test-agent/tests/protocol.test.ts": 580, + "packages/test-agent/tests/provider.test.ts": 1316, + "packages/test-agent/tests/public-api.test.ts": 1482, + "packages/test-agent/tests/route-slot.test.ts": 484, + "packages/test-agent/tests/smoke.test.ts": 27766, + "packages/test-agent/tests/template.test.ts": 1152, + "packages/test-agent/tests/worker-lifecycle.test.ts": 22654, + "packages/test-support/tests/journal.test.ts": 496, + "packages/testing/tests/agent-composition.test.ts": 1449, + "packages/testing/tests/assert-throws.test.ts": 2971, + "packages/testing/tests/assert.test.ts": 503, + "packages/testing/tests/assertions.test.ts": 3639, + "packages/testing/tests/boundary-contract.test.ts": 2389, + "packages/testing/tests/cli.test.ts": 10495, + "packages/testing/tests/execution-harness.test.ts": 6953, + "packages/testing/tests/replay.test.ts": 2885, + "packages/testing/tests/smoke.test.ts": 3072, + "packages/testing/tests/test-component.test.ts": 3838, + "packages/testing/tests/testing-activation.test.ts": 3222, + "packages/testing/tests/testing-boundary.test.ts": 1911, + "packages/testing/tests/testing-mode.test.ts": 3840, + "packages/testing/tests/use-testing.test.ts": 2610, + "packages/web/tests/assets.test.ts": 481, + "packages/web/tests/client-logic.test.ts": 526, + "packages/web/tests/compile.test.ts": 1866, + "packages/web/tests/component.test.ts": 2372, + "packages/web/tests/declaration.test.ts": 1607, + "packages/web/tests/document.test.ts": 1731, + "packages/web/tests/elicitation.test.ts": 1535, + "packages/web/tests/live-form.test.ts": 1443, + "packages/web/tests/markdown.test.ts": 739, + "packages/web/tests/opener.test.ts": 1428, + "packages/web/tests/page.test.ts": 497, + "packages/web/tests/responder.test.ts": 1747, + "packages/web/tests/server-lifecycle.test.ts": 1569, + "packages/web/tests/server.test.ts": 1985, + "packages/workflow/tests/generated-observations.test.ts": 1430, + "packages/workflow/tests/retained-run.test.ts": 2060, + "packages/workflow/tests/service-denial.test.ts": 511, + "packages/workflow/tests/workflow-bundle.test.ts": 1591, + "packages/workflow/tests/workflow-definition.test.ts": 1296, + "packages/workflow/tests/workflow-fork.test.ts": 1194, + "packages/workflow/tests/workflow-run.test.ts": 2017, + "packages/workflow/tests/workspace-effect.test.ts": 2865, + "packages/workflow/tests/xmd-artifact.test.ts": 3579, + "scripts/tests/adapter-vendor.test.ts": 702, + "scripts/tests/bootstrap-npm-package.test.ts": 7960, + "scripts/tests/bump-version.test.ts": 611, + "scripts/tests/changed-paths.test.ts": 507, + "scripts/tests/ci-workflow.test.ts": 3499, + "scripts/tests/consumer-cycle.test.ts": 668, + "scripts/tests/filesystem-contract-workflow.test.ts": 575, + "scripts/tests/main-green.test.ts": 754, + "scripts/tests/main-health.test.ts": 599, + "scripts/tests/no-module-scoped-registry.test.ts": 1318, + "scripts/tests/no-redundant-test-scope.test.ts": 5258, + "scripts/tests/no-sync-filesystem.test.ts": 5442, + "scripts/tests/no-yield-in-finally.test.ts": 1290, + "scripts/tests/oxlint-policy.test.ts": 10787, + "scripts/tests/packaged-document.test.ts": 586, + "scripts/tests/prefer-effection-operation.test.ts": 6260, + "scripts/tests/prefer-effection-result.test.ts": 4481, + "scripts/tests/publish-workflow-membership.test.ts": 628, + "scripts/tests/review-infrastructure.test.ts": 3036, + "scripts/tests/runtime-exclusions.test.ts": 953, + "scripts/tests/runtime-tests.test.ts": 537, + "scripts/tests/scope-bound-event-registration.test.ts": 5310, + "scripts/tests/staged-write.test.ts": 528, + "scripts/tests/test-file-discovery.test.ts": 782, + "scripts/tests/test-shards.test.ts": 520, + "scripts/tests/test-weights.test.ts": 709, + "scripts/tests/tracked.test.ts": 574, + "scripts/tests/verify-coordinator.test.ts": 717, + "scripts/tests/version-lockstep.test.ts": 688, + "scripts/tests/web-client-module.test.ts": 504, + "scripts/tests/workspace.test.ts": 498 }, "bun": { - "packages/acp/tests/acceptance.test.ts": 890, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4354, - "packages/acp/tests/acpx-materialization.test.ts": 6513, - "packages/acp/tests/acpx-transient-env.test.ts": 253, - "packages/acp/tests/adapter-materialization.test.ts": 71896, - "packages/acp/tests/adapter-protocol.test.ts": 54722, - "packages/acp/tests/codex-surfaces.test.ts": 124, - "packages/acp/tests/native-launch.test.ts": 997, + "packages/acp/tests/acceptance.test.ts": 802, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4312, + "packages/acp/tests/acpx-materialization.test.ts": 6507, + "packages/acp/tests/acpx-transient-env.test.ts": 259, + "packages/acp/tests/adapter-materialization.test.ts": 69531, + "packages/acp/tests/adapter-protocol.test.ts": 52429, + "packages/acp/tests/codex-surfaces.test.ts": 154, + "packages/acp/tests/native-launch.test.ts": 1069, "packages/acp/tests/permission-bridge.test.ts": 359, - "packages/acp/tests/provider.test.ts": 1112, - "packages/acp/tests/serial-queue.test.ts": 69, - "packages/acp/tests/session-key.test.ts": 69, - "packages/acp/tests/terminal-screen.test.ts": 97, - "packages/cli/tests/agent-adapters.test.ts": 1196, - "packages/cli/tests/agent-cli.test.ts": 20602, - "packages/cli/tests/agent-config.test.ts": 30, - "packages/cli/tests/agent-options-cli.test.ts": 7840, - "packages/cli/tests/agent-options.test.ts": 34, - "packages/cli/tests/agent-session-coordinator.test.ts": 443, - "packages/cli/tests/cli-help.test.ts": 16040, - "packages/cli/tests/command.test.ts": 7978, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 3100, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 106189, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 2340, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 5163, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 4831, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 8968, - "packages/cli/tests/evaluate-component.test.ts": 7888, - "packages/cli/tests/fetch-cli.test.ts": 2329, - "packages/cli/tests/file-stream.test.ts": 56, - "packages/cli/tests/inline-cli.test.ts": 32163, - "packages/cli/tests/launch-timeout.test.ts": 10092, - "packages/cli/tests/packaged-document.test.ts": 471, - "packages/cli/tests/plan-args.test.ts": 37, - "packages/cli/tests/plan-cli.test.ts": 58708, - "packages/cli/tests/plan-command-document.test.ts": 5339, - "packages/cli/tests/plan-component.test.ts": 8740, - "packages/cli/tests/plan-host-acts.test.ts": 1166, - "packages/cli/tests/plan.test.ts": 13069, - "packages/cli/tests/plugin-cli.test.ts": 39698, - "packages/cli/tests/plugin-host.test.ts": 2058, + "packages/acp/tests/provider.test.ts": 1114, + "packages/acp/tests/serial-queue.test.ts": 67, + "packages/acp/tests/session-key.test.ts": 64, + "packages/acp/tests/terminal-screen.test.ts": 90, + "packages/cli/tests/agent-adapters.test.ts": 1164, + "packages/cli/tests/agent-cli.test.ts": 20197, + "packages/cli/tests/agent-config.test.ts": 29, + "packages/cli/tests/agent-options-cli.test.ts": 7702, + "packages/cli/tests/agent-options.test.ts": 35, + "packages/cli/tests/agent-session-coordinator.test.ts": 393, + "packages/cli/tests/cli-help.test.ts": 15419, + "packages/cli/tests/command.test.ts": 7815, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 2837, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 103938, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 2210, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 4691, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 4448, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 8611, + "packages/cli/tests/evaluate-component.test.ts": 7498, + "packages/cli/tests/fetch-cli.test.ts": 2356, + "packages/cli/tests/file-stream.test.ts": 55, + "packages/cli/tests/inline-cli.test.ts": 30692, + "packages/cli/tests/launch-timeout.test.ts": 10096, + "packages/cli/tests/packaged-document.test.ts": 447, + "packages/cli/tests/plan-args.test.ts": 35, + "packages/cli/tests/plan-cli.test.ts": 58259, + "packages/cli/tests/plan-command-document.test.ts": 5727, + "packages/cli/tests/plan-component.test.ts": 9205, + "packages/cli/tests/plan-host-acts.test.ts": 1239, + "packages/cli/tests/plan.test.ts": 12979, + "packages/cli/tests/plugin-cli.test.ts": 39305, + "packages/cli/tests/plugin-host.test.ts": 2072, "packages/cli/tests/plugin-modules.test.ts": 39, "packages/cli/tests/plugin-selection.test.ts": 38, - "packages/cli/tests/process-retention.test.ts": 2449, - "packages/cli/tests/props-cli.test.ts": 28963, - "packages/cli/tests/props-schema.test.ts": 432, - "packages/cli/tests/props-sources.test.ts": 125, - "packages/cli/tests/repl-boundaries.test.ts": 1294, - "packages/cli/tests/repl-composition.test.ts": 147, - "packages/cli/tests/repl-execution.test.ts": 1941, - "packages/cli/tests/repl-journey.test.ts": 10292, - "packages/cli/tests/repl-model.test.ts": 1718, - "packages/cli/tests/repl-route.test.ts": 1238, - "packages/cli/tests/repl-terminal.test.ts": 840, - "packages/cli/tests/run-composition.test.ts": 3125, - "packages/cli/tests/run-deadline.test.ts": 2377, - "packages/cli/tests/run-profile.test.ts": 312, - "packages/cli/tests/run-timeouts.test.ts": 11379, - "packages/cli/tests/secret-detection-cli.test.ts": 18442, - "packages/cli/tests/service-document.test.ts": 1524, - "packages/cli/tests/service-host.test.ts": 1402, - "packages/cli/tests/session-launch-cli.test.ts": 5637, - "packages/cli/tests/stdin-cli.test.ts": 31362, - "packages/cli/tests/stdout-delivery.test.ts": 54, - "packages/cli/tests/syntax-cli.test.ts": 33389, - "packages/cli/tests/targets-cli.test.ts": 22183, - "packages/cli/tests/test-root-profile.test.ts": 3765, - "packages/cli/tests/test-target.test.ts": 36487, - "packages/cli/tests/testing-activation.test.ts": 581, - "packages/cli/tests/testing-execution-host.test.ts": 49745, - "packages/cli/tests/upgrade-cli.test.ts": 18478, - "packages/cli/tests/upgrade-command-document.test.ts": 3538, - "packages/cli/tests/upgrade-output.test.ts": 830, - "packages/cli/tests/value-root.test.ts": 16272, - "packages/cli/tests/verbose-component.test.ts": 818, - "packages/cli/tests/workflow-declaration.test.ts": 551, - "packages/cli/tests/workflow-host.test.ts": 4237, - "packages/code-review-agent/tests/doctor.test.ts": 29, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 41, - "packages/code-review-agent/tests/parse-diff.test.ts": 36, - "packages/code-review-agent/tests/parse-doctor.test.ts": 296, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 31, - "packages/code-review-agent/tests/policy.test.ts": 35, - "packages/core/tests/agent-api.test.ts": 40, - "packages/core/tests/agent-components.test.ts": 1263, - "packages/core/tests/agent-function-components.test.ts": 3627, - "packages/core/tests/agent-session-launch.test.ts": 3441, - "packages/core/tests/agent-session-placement.test.ts": 37, - "packages/core/tests/agent-session-use.test.ts": 34, - "packages/core/tests/agent-stack.test.ts": 767, - "packages/core/tests/all.test.ts": 2117, - "packages/core/tests/answer-identity.test.ts": 62, - "packages/core/tests/answers-component.test.ts": 1395, - "packages/core/tests/answers-expansion-recursion.test.ts": 326, - "packages/core/tests/capture-errors.test.ts": 617, - "packages/core/tests/capture-props.test.ts": 337, - "packages/core/tests/cli-journal.test.ts": 10770, - "packages/core/tests/code-block-component.test.ts": 2652, - "packages/core/tests/compiler-boundary.test.ts": 349, + "packages/cli/tests/process-retention.test.ts": 2532, + "packages/cli/tests/props-cli.test.ts": 29054, + "packages/cli/tests/props-schema.test.ts": 414, + "packages/cli/tests/props-sources.test.ts": 119, + "packages/cli/tests/repl-boundaries.test.ts": 1165, + "packages/cli/tests/repl-composition.test.ts": 138, + "packages/cli/tests/repl-execution.test.ts": 1868, + "packages/cli/tests/repl-journey.test.ts": 10385, + "packages/cli/tests/repl-model.test.ts": 1645, + "packages/cli/tests/repl-route.test.ts": 1217, + "packages/cli/tests/repl-terminal.test.ts": 881, + "packages/cli/tests/run-composition.test.ts": 2872, + "packages/cli/tests/run-deadline.test.ts": 2388, + "packages/cli/tests/run-profile.test.ts": 307, + "packages/cli/tests/run-timeouts.test.ts": 11100, + "packages/cli/tests/secret-detection-cli.test.ts": 17659, + "packages/cli/tests/service-document.test.ts": 1617, + "packages/cli/tests/service-host.test.ts": 1505, + "packages/cli/tests/session-launch-cli.test.ts": 5447, + "packages/cli/tests/stdin-cli.test.ts": 30139, + "packages/cli/tests/stdout-delivery.test.ts": 50, + "packages/cli/tests/syntax-cli.test.ts": 31494, + "packages/cli/tests/targets-cli.test.ts": 21382, + "packages/cli/tests/test-root-profile.test.ts": 3462, + "packages/cli/tests/test-target.test.ts": 34931, + "packages/cli/tests/testing-activation.test.ts": 538, + "packages/cli/tests/testing-execution-host.test.ts": 47835, + "packages/cli/tests/upgrade-cli.test.ts": 17841, + "packages/cli/tests/upgrade-command-document.test.ts": 3534, + "packages/cli/tests/upgrade-output.test.ts": 785, + "packages/cli/tests/value-root.test.ts": 15455, + "packages/cli/tests/verbose-component.test.ts": 781, + "packages/cli/tests/workflow-declaration.test.ts": 513, + "packages/cli/tests/workflow-host.test.ts": 4039, + "packages/code-review-agent/tests/doctor.test.ts": 30, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 63, + "packages/code-review-agent/tests/parse-diff.test.ts": 52, + "packages/code-review-agent/tests/parse-doctor.test.ts": 298, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 29, + "packages/code-review-agent/tests/policy.test.ts": 32, + "packages/core/tests/agent-api.test.ts": 37, + "packages/core/tests/agent-components.test.ts": 1176, + "packages/core/tests/agent-function-components.test.ts": 3357, + "packages/core/tests/agent-session-launch.test.ts": 3472, + "packages/core/tests/agent-session-placement.test.ts": 38, + "packages/core/tests/agent-session-use.test.ts": 33, + "packages/core/tests/agent-stack.test.ts": 699, + "packages/core/tests/all.test.ts": 2046, + "packages/core/tests/answer-identity.test.ts": 65, + "packages/core/tests/answers-component.test.ts": 1466, + "packages/core/tests/answers-expansion-recursion.test.ts": 307, + "packages/core/tests/capture-errors.test.ts": 573, + "packages/core/tests/capture-props.test.ts": 328, + "packages/core/tests/cli-journal.test.ts": 10236, + "packages/core/tests/code-block-component.test.ts": 2298, + "packages/core/tests/compiler-boundary.test.ts": 337, "packages/core/tests/component-api.test.ts": 54, - "packages/core/tests/component-registration.test.ts": 1268, - "packages/core/tests/component-returns.test.ts": 1728, - "packages/core/tests/component-schema-conformance.test.ts": 576, - "packages/core/tests/config-api.test.ts": 357, - "packages/core/tests/construct-error-observation.test.ts": 787, - "packages/core/tests/contextual-cwd.test.ts": 1558, - "packages/core/tests/daemon-integration.test.ts": 1063, - "packages/core/tests/daemon.test.ts": 77, - "packages/core/tests/declared-markdown-component.test.ts": 2195, - "packages/core/tests/document-output-api.test.ts": 40, - "packages/core/tests/document-target-execution.test.ts": 3846, - "packages/core/tests/document-targets.test.ts": 446, - "packages/core/tests/document-validation.test.ts": 2234, - "packages/core/tests/documentation-index.test.ts": 172, - "packages/core/tests/each.test.ts": 435, - "packages/core/tests/elicit-component.test.ts": 1156, - "packages/core/tests/ephemeral-service.test.ts": 883, - "packages/core/tests/eval-bindings.test.ts": 422, - "packages/core/tests/eval-context.test.ts": 88, - "packages/core/tests/eval-durable.test.ts": 463, - "packages/core/tests/eval-error-mode.test.ts": 701, - "packages/core/tests/eval-interpolate.test.ts": 39, - "packages/core/tests/eval-middleware.test.ts": 78, - "packages/core/tests/eval-persist.test.ts": 520, - "packages/core/tests/eval-return.test.ts": 452, - "packages/core/tests/eval-scope.test.ts": 352, - "packages/core/tests/eval-timeout.test.ts": 462, - "packages/core/tests/eval-transform.test.ts": 65, - "packages/core/tests/evaluate-component.test.ts": 2630, - "packages/core/tests/evaluate-loaded-copy.test.ts": 535, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 660, - "packages/core/tests/evaluation-profile.test.ts": 205, - "packages/core/tests/exec-timeout.test.ts": 526, - "packages/core/tests/execute.test.ts": 1048, - "packages/core/tests/execution-protocol.test.ts": 1714, - "packages/core/tests/expand.test.ts": 1380, - "packages/core/tests/expansion-identity.test.ts": 1315, - "packages/core/tests/expansion-metadata.test.ts": 364, - "packages/core/tests/expression-props.test.ts": 958, - "packages/core/tests/fail-component.test.ts": 805, - "packages/core/tests/failure-printing.test.ts": 713, - "packages/core/tests/fatal-cause.test.ts": 200, - "packages/core/tests/fetch-component.test.ts": 1878, - "packages/core/tests/file-component.test.ts": 2550, - "packages/core/tests/file-delete-component.test.ts": 643, - "packages/core/tests/files-fatal.test.ts": 1613, - "packages/core/tests/foreground-exec.test.ts": 1329, - "packages/core/tests/frontmatter.test.ts": 52, - "packages/core/tests/function-components.test.ts": 972, - "packages/core/tests/generated-composition.test.ts": 1221, - "packages/core/tests/generated-xmd.test.ts": 2533, - "packages/core/tests/glob-api.test.ts": 101, - "packages/core/tests/glob-component.test.ts": 1289, - "packages/core/tests/guarded-journal.test.ts": 484, - "packages/core/tests/has-content.test.ts": 280, - "packages/core/tests/heal.test.ts": 273, - "packages/core/tests/if.test.ts": 872, - "packages/core/tests/inline-root.test.ts": 514, - "packages/core/tests/invocation-failures.test.ts": 107, - "packages/core/tests/invocation-identity.test.ts": 923, - "packages/core/tests/invocation-scope.test.ts": 573, - "packages/core/tests/journal-source-position.test.ts": 597, - "packages/core/tests/json-component.test.ts": 2468, - "packages/core/tests/json.test.ts": 35, - "packages/core/tests/let.test.ts": 437, - "packages/core/tests/loop.test.ts": 1331, - "packages/core/tests/named-slots.test.ts": 1353, - "packages/core/tests/output-error-mode.test.ts": 1664, - "packages/core/tests/output-normalize.test.ts": 44, - "packages/core/tests/output-terminal.test.ts": 165, - "packages/core/tests/parse-components.test.ts": 660, - "packages/core/tests/plan-response.test.ts": 88, - "packages/core/tests/plugin-api.test.ts": 49, - "packages/core/tests/plugin.test.ts": 200, - "packages/core/tests/props-binding.test.ts": 567, - "packages/core/tests/protected-content.test.ts": 53, - "packages/core/tests/registered-printed-errors.test.ts": 223, - "packages/core/tests/replay-stream.test.ts": 38, - "packages/core/tests/retain.test.ts": 500, - "packages/core/tests/root-composition.test.ts": 596, - "packages/core/tests/root-props.test.ts": 630, - "packages/core/tests/root-provider.test.ts": 662, - "packages/core/tests/sample-component.test.ts": 1260, - "packages/core/tests/scanner.test.ts": 82, - "packages/core/tests/scope-local.test.ts": 38, - "packages/core/tests/secret-detection.test.ts": 1204, - "packages/core/tests/secret-files.test.ts": 130, - "packages/core/tests/secret-rules.test.ts": 164, - "packages/core/tests/secret-scanner-baseline.test.ts": 156, + "packages/core/tests/component-registration.test.ts": 1097, + "packages/core/tests/component-returns.test.ts": 1631, + "packages/core/tests/component-schema-conformance.test.ts": 544, + "packages/core/tests/config-api.test.ts": 340, + "packages/core/tests/construct-error-observation.test.ts": 697, + "packages/core/tests/contextual-cwd.test.ts": 1524, + "packages/core/tests/daemon-integration.test.ts": 1010, + "packages/core/tests/daemon.test.ts": 70, + "packages/core/tests/declared-markdown-component.test.ts": 2010, + "packages/core/tests/document-output-api.test.ts": 39, + "packages/core/tests/document-target-execution.test.ts": 3538, + "packages/core/tests/document-targets.test.ts": 428, + "packages/core/tests/document-validation.test.ts": 2141, + "packages/core/tests/documentation-index.test.ts": 166, + "packages/core/tests/each.test.ts": 417, + "packages/core/tests/elicit-component.test.ts": 1150, + "packages/core/tests/ephemeral-service.test.ts": 806, + "packages/core/tests/eval-bindings.test.ts": 390, + "packages/core/tests/eval-context.test.ts": 91, + "packages/core/tests/eval-durable.test.ts": 426, + "packages/core/tests/eval-error-mode.test.ts": 683, + "packages/core/tests/eval-interpolate.test.ts": 40, + "packages/core/tests/eval-middleware.test.ts": 72, + "packages/core/tests/eval-persist.test.ts": 494, + "packages/core/tests/eval-return.test.ts": 418, + "packages/core/tests/eval-scope.test.ts": 319, + "packages/core/tests/eval-timeout.test.ts": 428, + "packages/core/tests/eval-transform.test.ts": 120, + "packages/core/tests/evaluate-component.test.ts": 2516, + "packages/core/tests/evaluate-loaded-copy.test.ts": 508, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 579, + "packages/core/tests/evaluation-profile.test.ts": 193, + "packages/core/tests/exec-timeout.test.ts": 484, + "packages/core/tests/execute.test.ts": 1057, + "packages/core/tests/execution-protocol.test.ts": 1568, + "packages/core/tests/expand.test.ts": 1254, + "packages/core/tests/expansion-identity.test.ts": 1244, + "packages/core/tests/expansion-metadata.test.ts": 356, + "packages/core/tests/expression-props.test.ts": 918, + "packages/core/tests/fail-component.test.ts": 783, + "packages/core/tests/failure-printing.test.ts": 738, + "packages/core/tests/fatal-cause.test.ts": 186, + "packages/core/tests/fetch-component.test.ts": 1866, + "packages/core/tests/file-component.test.ts": 2451, + "packages/core/tests/file-delete-component.test.ts": 656, + "packages/core/tests/files-fatal.test.ts": 1525, + "packages/core/tests/foreground-exec.test.ts": 1346, + "packages/core/tests/frontmatter.test.ts": 49, + "packages/core/tests/function-components.test.ts": 904, + "packages/core/tests/generated-composition.test.ts": 1169, + "packages/core/tests/generated-xmd.test.ts": 2477, + "packages/core/tests/glob-api.test.ts": 97, + "packages/core/tests/glob-component.test.ts": 1266, + "packages/core/tests/guarded-journal.test.ts": 437, + "packages/core/tests/has-content.test.ts": 277, + "packages/core/tests/heal.test.ts": 255, + "packages/core/tests/if.test.ts": 829, + "packages/core/tests/inline-root.test.ts": 513, + "packages/core/tests/invocation-failures.test.ts": 112, + "packages/core/tests/invocation-identity.test.ts": 860, + "packages/core/tests/invocation-scope.test.ts": 548, + "packages/core/tests/journal-source-position.test.ts": 614, + "packages/core/tests/json-component.test.ts": 2494, + "packages/core/tests/json.test.ts": 33, + "packages/core/tests/let.test.ts": 419, + "packages/core/tests/loop.test.ts": 1225, + "packages/core/tests/named-slots.test.ts": 1266, + "packages/core/tests/output-error-mode.test.ts": 1615, + "packages/core/tests/output-normalize.test.ts": 40, + "packages/core/tests/output-terminal.test.ts": 163, + "packages/core/tests/parse-components.test.ts": 693, + "packages/core/tests/plan-response.test.ts": 80, + "packages/core/tests/plugin-api.test.ts": 44, + "packages/core/tests/plugin.test.ts": 190, + "packages/core/tests/props-binding.test.ts": 557, + "packages/core/tests/protected-content.test.ts": 55, + "packages/core/tests/registered-printed-errors.test.ts": 202, + "packages/core/tests/replay-stream.test.ts": 37, + "packages/core/tests/retain.test.ts": 451, + "packages/core/tests/root-composition.test.ts": 563, + "packages/core/tests/root-props.test.ts": 588, + "packages/core/tests/root-provider.test.ts": 558, + "packages/core/tests/sample-component.test.ts": 1102, + "packages/core/tests/scanner.test.ts": 76, + "packages/core/tests/scope-local.test.ts": 34, + "packages/core/tests/secret-detection.test.ts": 1113, + "packages/core/tests/secret-files.test.ts": 131, + "packages/core/tests/secret-rules.test.ts": 152, + "packages/core/tests/secret-scanner-baseline.test.ts": 151, "packages/core/tests/secret-scanner.test.ts": 103, - "packages/core/tests/source-position.test.ts": 364, - "packages/core/tests/state-ownership.test.ts": 421, - "packages/core/tests/streaming-emission.test.ts": 335, - "packages/core/tests/switch.test.ts": 884, - "packages/core/tests/syntax-catalog.test.ts": 962, - "packages/core/tests/syntax-component.test.ts": 1905, - "packages/core/tests/temp-dir.test.ts": 2876, - "packages/core/tests/temp-file-compiler.test.ts": 85, - "packages/core/tests/text-interpolation.test.ts": 242, - "packages/core/tests/try-content.test.ts": 281, - "packages/core/tests/unused-in-diff.test.ts": 529, - "packages/core/tests/validate.test.ts": 346, - "packages/core/tests/validation-integration.test.ts": 383, - "packages/core/tests/workflow-component-bundle.test.ts": 780, - "packages/durable-streams/tests/context.test.ts": 38, - "packages/durable-streams/tests/deterministic-id.test.ts": 78, - "packages/durable-streams/tests/divergence-api.test.ts": 49, - "packages/durable-streams/tests/divergence.test.ts": 61, - "packages/durable-streams/tests/durable-each.test.ts": 74, - "packages/durable-streams/tests/durable-position.test.ts": 58, - "packages/durable-streams/tests/durable-run.test.ts": 68, - "packages/durable-streams/tests/ephemeral.test.ts": 65, - "packages/durable-streams/tests/fail-stop.test.ts": 77, - "packages/durable-streams/tests/guard-stream.test.ts": 103, - "packages/durable-streams/tests/live-coordinator.test.ts": 62, - "packages/durable-streams/tests/parse.test.ts": 52, - "packages/durable-streams/tests/replay-guard.test.ts": 75, - "packages/durable-streams/tests/replay-index.test.ts": 46, - "packages/durable-streams/tests/retained.test.ts": 45, - "packages/durable-streams/tests/serialize-event.test.ts": 43, - "packages/durable-streams/tests/smoke.test.ts": 49, - "packages/durable-streams/tests/structured-concurrency.test.ts": 148, - "packages/durable-streams/tests/terminal-boundary.test.ts": 79, - "packages/durable-streams/tests/types.test.ts": 30, - "packages/git/tests/api-entrypoint.test.ts": 330, - "packages/git/tests/git-host-effect.test.ts": 6986, - "packages/git/tests/git.test.ts": 405, - "packages/git/tests/github-activation.test.ts": 765, - "packages/git/tests/github-issues.test.ts": 337, - "packages/git/tests/github-pull-requests.test.ts": 86, - "packages/git/tests/issue-markdown.test.ts": 9264, - "packages/git/tests/issue-records.test.ts": 311, - "packages/git/tests/module-partition.test.ts": 1988, - "packages/git/tests/plugin.test.ts": 846, - "packages/git/tests/provider-neutrality.test.ts": 1117, - "packages/git/tests/pull-request-records.test.ts": 339, - "packages/git/tests/run-composition-lazy.test.ts": 843, + "packages/core/tests/source-position.test.ts": 324, + "packages/core/tests/state-ownership.test.ts": 391, + "packages/core/tests/streaming-emission.test.ts": 309, + "packages/core/tests/switch.test.ts": 912, + "packages/core/tests/syntax-catalog.test.ts": 884, + "packages/core/tests/syntax-component.test.ts": 1735, + "packages/core/tests/temp-dir.test.ts": 2806, + "packages/core/tests/temp-file-compiler.test.ts": 81, + "packages/core/tests/text-interpolation.test.ts": 225, + "packages/core/tests/try-content.test.ts": 264, + "packages/core/tests/unused-in-diff.test.ts": 475, + "packages/core/tests/validate.test.ts": 300, + "packages/core/tests/validation-integration.test.ts": 361, + "packages/core/tests/workflow-component-bundle.test.ts": 701, + "packages/durable-streams/tests/context.test.ts": 37, + "packages/durable-streams/tests/deterministic-id.test.ts": 67, + "packages/durable-streams/tests/divergence-api.test.ts": 45, + "packages/durable-streams/tests/divergence.test.ts": 57, + "packages/durable-streams/tests/durable-each.test.ts": 63, + "packages/durable-streams/tests/durable-position.test.ts": 54, + "packages/durable-streams/tests/durable-run.test.ts": 64, + "packages/durable-streams/tests/ephemeral.test.ts": 61, + "packages/durable-streams/tests/fail-stop.test.ts": 73, + "packages/durable-streams/tests/guard-stream.test.ts": 99, + "packages/durable-streams/tests/live-coordinator.test.ts": 56, + "packages/durable-streams/tests/parse.test.ts": 50, + "packages/durable-streams/tests/replay-guard.test.ts": 71, + "packages/durable-streams/tests/replay-index.test.ts": 45, + "packages/durable-streams/tests/retained.test.ts": 63, + "packages/durable-streams/tests/serialize-event.test.ts": 83, + "packages/durable-streams/tests/smoke.test.ts": 34, + "packages/durable-streams/tests/structured-concurrency.test.ts": 88, + "packages/durable-streams/tests/terminal-boundary.test.ts": 75, + "packages/durable-streams/tests/types.test.ts": 29, + "packages/git/tests/api-entrypoint.test.ts": 297, + "packages/git/tests/git-host-effect.test.ts": 7018, + "packages/git/tests/git.test.ts": 414, + "packages/git/tests/github-activation.test.ts": 825, + "packages/git/tests/github-issues.test.ts": 335, + "packages/git/tests/github-pull-requests.test.ts": 88, + "packages/git/tests/issue-markdown.test.ts": 8832, + "packages/git/tests/issue-records.test.ts": 291, + "packages/git/tests/module-partition.test.ts": 1763, + "packages/git/tests/plugin.test.ts": 903, + "packages/git/tests/provider-neutrality.test.ts": 1061, + "packages/git/tests/pull-request-records.test.ts": 326, + "packages/git/tests/run-composition-lazy.test.ts": 824, "packages/git/tests/selection-authentication.test.ts": 40, - "packages/runtime/tests/duration.test.ts": 31, - "packages/runtime/tests/fetch.test.ts": 623, + "packages/runtime/tests/duration.test.ts": 33, + "packages/runtime/tests/fetch.test.ts": 629, "packages/runtime/tests/fs.test.ts": 70, - "packages/runtime/tests/host-files.test.ts": 735, - "packages/runtime/tests/native-launcher.test.ts": 2428, - "packages/runtime/tests/process.test.ts": 96, - "packages/runtime/tests/service.test.ts": 64, - "packages/test-agent/tests/acp-server.test.ts": 113, - "packages/test-agent/tests/behavior-engine.test.ts": 713, - "packages/test-agent/tests/bridge.test.ts": 71, - "packages/test-agent/tests/command-lazy.test.ts": 3362, - "packages/test-agent/tests/components.test.ts": 54248, - "packages/test-agent/tests/controller.test.ts": 217, - "packages/test-agent/tests/cross-package-resolution.test.ts": 1962, - "packages/test-agent/tests/native-launch.test.ts": 25442, - "packages/test-agent/tests/net.test.ts": 105, - "packages/test-agent/tests/profile.test.ts": 320, - "packages/test-agent/tests/protocol.test.ts": 63, - "packages/test-agent/tests/provider.test.ts": 429, - "packages/test-agent/tests/public-api.test.ts": 504, - "packages/test-agent/tests/route-slot.test.ts": 60, - "packages/test-agent/tests/smoke.test.ts": 16103, - "packages/test-agent/tests/template.test.ts": 312, - "packages/test-agent/tests/worker-lifecycle.test.ts": 9757, - "packages/test-support/tests/journal.test.ts": 44, - "packages/testing/tests/agent-composition.test.ts": 673, - "packages/testing/tests/assert-throws.test.ts": 2560, - "packages/testing/tests/assert.test.ts": 58, - "packages/testing/tests/assertions.test.ts": 3361, - "packages/testing/tests/boundary-contract.test.ts": 1777, - "packages/testing/tests/cli.test.ts": 5285, - "packages/testing/tests/execution-harness.test.ts": 7412, - "packages/testing/tests/replay.test.ts": 2320, - "packages/testing/tests/smoke.test.ts": 1999, - "packages/testing/tests/test-component.test.ts": 3228, - "packages/testing/tests/testing-activation.test.ts": 2839, - "packages/testing/tests/testing-boundary.test.ts": 1196, - "packages/testing/tests/testing-mode.test.ts": 3302, - "packages/testing/tests/use-testing.test.ts": 1960, - "packages/web/tests/assets.test.ts": 32, - "packages/web/tests/client-logic.test.ts": 39, - "packages/web/tests/compile.test.ts": 966, - "packages/web/tests/component.test.ts": 1541, - "packages/web/tests/declaration.test.ts": 737, - "packages/web/tests/document.test.ts": 798, - "packages/web/tests/elicitation.test.ts": 568, - "packages/web/tests/live-form.test.ts": 527, - "packages/web/tests/markdown.test.ts": 146, - "packages/web/tests/opener.test.ts": 496, - "packages/web/tests/page.test.ts": 35, - "packages/web/tests/responder.test.ts": 895, - "packages/web/tests/server-lifecycle.test.ts": 661, - "packages/web/tests/server.test.ts": 1089, - "packages/workflow/tests/generated-observations.test.ts": 633, - "packages/workflow/tests/retained-run.test.ts": 1392, - "packages/workflow/tests/service-denial.test.ts": 72, - "packages/workflow/tests/workflow-bundle.test.ts": 793, - "packages/workflow/tests/workflow-definition.test.ts": 377, - "packages/workflow/tests/workflow-fork.test.ts": 320, - "packages/workflow/tests/workflow-run.test.ts": 1193, - "packages/workflow/tests/workspace-effect.test.ts": 1588, - "scripts/tests/adapter-vendor.test.ts": 165, - "scripts/tests/bootstrap-npm-package.test.ts": 6390, - "scripts/tests/bump-version.test.ts": 99, - "scripts/tests/changed-paths.test.ts": 44, - "scripts/tests/ci-workflow.test.ts": 2072, - "scripts/tests/consumer-cycle.test.ts": 117, + "packages/runtime/tests/host-files.test.ts": 733, + "packages/runtime/tests/native-launcher.test.ts": 2442, + "packages/runtime/tests/process.test.ts": 89, + "packages/runtime/tests/service.test.ts": 66, + "packages/test-agent/tests/acp-server.test.ts": 114, + "packages/test-agent/tests/behavior-engine.test.ts": 714, + "packages/test-agent/tests/bridge.test.ts": 68, + "packages/test-agent/tests/command-lazy.test.ts": 3368, + "packages/test-agent/tests/components.test.ts": 52666, + "packages/test-agent/tests/controller.test.ts": 207, + "packages/test-agent/tests/cross-package-resolution.test.ts": 1852, + "packages/test-agent/tests/native-launch.test.ts": 24354, + "packages/test-agent/tests/net.test.ts": 104, + "packages/test-agent/tests/profile.test.ts": 306, + "packages/test-agent/tests/protocol.test.ts": 58, + "packages/test-agent/tests/provider.test.ts": 398, + "packages/test-agent/tests/public-api.test.ts": 466, + "packages/test-agent/tests/route-slot.test.ts": 58, + "packages/test-agent/tests/smoke.test.ts": 15428, + "packages/test-agent/tests/template.test.ts": 287, + "packages/test-agent/tests/worker-lifecycle.test.ts": 9194, + "packages/test-support/tests/journal.test.ts": 41, + "packages/testing/tests/agent-composition.test.ts": 606, + "packages/testing/tests/assert-throws.test.ts": 2229, + "packages/testing/tests/assert.test.ts": 57, + "packages/testing/tests/assertions.test.ts": 2955, + "packages/testing/tests/boundary-contract.test.ts": 1574, + "packages/testing/tests/cli.test.ts": 4937, + "packages/testing/tests/execution-harness.test.ts": 6752, + "packages/testing/tests/replay.test.ts": 2277, + "packages/testing/tests/smoke.test.ts": 1870, + "packages/testing/tests/test-component.test.ts": 2935, + "packages/testing/tests/testing-activation.test.ts": 2541, + "packages/testing/tests/testing-boundary.test.ts": 1079, + "packages/testing/tests/testing-mode.test.ts": 3038, + "packages/testing/tests/use-testing.test.ts": 1759, + "packages/web/tests/assets.test.ts": 44, + "packages/web/tests/client-logic.test.ts": 61, + "packages/web/tests/compile.test.ts": 925, + "packages/web/tests/component.test.ts": 1458, + "packages/web/tests/declaration.test.ts": 669, + "packages/web/tests/document.test.ts": 763, + "packages/web/tests/elicitation.test.ts": 544, + "packages/web/tests/live-form.test.ts": 500, + "packages/web/tests/markdown.test.ts": 135, + "packages/web/tests/opener.test.ts": 483, + "packages/web/tests/page.test.ts": 33, + "packages/web/tests/responder.test.ts": 837, + "packages/web/tests/server-lifecycle.test.ts": 621, + "packages/web/tests/server.test.ts": 1031, + "packages/workflow/tests/generated-observations.test.ts": 591, + "packages/workflow/tests/retained-run.test.ts": 1209, + "packages/workflow/tests/service-denial.test.ts": 67, + "packages/workflow/tests/workflow-bundle.test.ts": 724, + "packages/workflow/tests/workflow-definition.test.ts": 343, + "packages/workflow/tests/workflow-fork.test.ts": 300, + "packages/workflow/tests/workflow-run.test.ts": 1070, + "packages/workflow/tests/workspace-effect.test.ts": 1378, + "scripts/tests/adapter-vendor.test.ts": 155, + "scripts/tests/bootstrap-npm-package.test.ts": 5520, + "scripts/tests/bump-version.test.ts": 82, + "scripts/tests/changed-paths.test.ts": 39, + "scripts/tests/ci-workflow.test.ts": 1899, + "scripts/tests/consumer-cycle.test.ts": 106, "scripts/tests/filesystem-contract-workflow.test.ts": 81, - "scripts/tests/main-green.test.ts": 304, - "scripts/tests/main-health.test.ts": 108, - "scripts/tests/no-module-scoped-registry.test.ts": 936, - "scripts/tests/no-redundant-test-scope.test.ts": 5136, - "scripts/tests/no-sync-filesystem.test.ts": 4757, - "scripts/tests/no-yield-in-finally.test.ts": 921, - "scripts/tests/oxlint-policy.test.ts": 10843, - "scripts/tests/packaged-document.test.ts": 86, - "scripts/tests/prefer-effection-operation.test.ts": 6274, - "scripts/tests/prefer-effection-result.test.ts": 4291, - "scripts/tests/publish-workflow-membership.test.ts": 108, - "scripts/tests/review-infrastructure.test.ts": 2038, - "scripts/tests/runtime-exclusions.test.ts": 344, - "scripts/tests/runtime-tests.test.ts": 80, - "scripts/tests/scope-bound-event-registration.test.ts": 4757, - "scripts/tests/staged-write.test.ts": 75, - "scripts/tests/test-file-discovery.test.ts": 267, - "scripts/tests/test-shards.test.ts": 47, - "scripts/tests/test-weights.test.ts": 216, - "scripts/tests/tracked.test.ts": 40, - "scripts/tests/verify-coordinator.test.ts": 228, - "scripts/tests/version-lockstep.test.ts": 127, - "scripts/tests/web-client-module.test.ts": 61, - "scripts/tests/workspace.test.ts": 51 + "scripts/tests/main-green.test.ts": 296, + "scripts/tests/main-health.test.ts": 100, + "scripts/tests/no-module-scoped-registry.test.ts": 889, + "scripts/tests/no-redundant-test-scope.test.ts": 4955, + "scripts/tests/no-sync-filesystem.test.ts": 4509, + "scripts/tests/no-yield-in-finally.test.ts": 893, + "scripts/tests/oxlint-policy.test.ts": 10632, + "scripts/tests/packaged-document.test.ts": 73, + "scripts/tests/prefer-effection-operation.test.ts": 6080, + "scripts/tests/prefer-effection-result.test.ts": 4135, + "scripts/tests/publish-workflow-membership.test.ts": 96, + "scripts/tests/review-infrastructure.test.ts": 1767, + "scripts/tests/runtime-exclusions.test.ts": 300, + "scripts/tests/runtime-tests.test.ts": 77, + "scripts/tests/scope-bound-event-registration.test.ts": 4462, + "scripts/tests/staged-write.test.ts": 65, + "scripts/tests/test-file-discovery.test.ts": 233, + "scripts/tests/test-shards.test.ts": 43, + "scripts/tests/test-weights.test.ts": 206, + "scripts/tests/tracked.test.ts": 38, + "scripts/tests/verify-coordinator.test.ts": 222, + "scripts/tests/version-lockstep.test.ts": 116, + "scripts/tests/web-client-module.test.ts": 59, + "scripts/tests/workspace.test.ts": 45 } } } From 1d317942eb24810816c172998c083033f5d1165b Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 09:41:06 -0400 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=90=9B=20Retain=20reused=20componen?= =?UTF-8?q?t=20answers=20once?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/component-resolution.ts | 19 ++++--- packages/core/tests/answer-identity.test.ts | 53 +++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/packages/core/src/components/component-resolution.ts b/packages/core/src/components/component-resolution.ts index 646e777a5..a87d65fc0 100644 --- a/packages/core/src/components/component-resolution.ts +++ b/packages/core/src/components/component-resolution.ts @@ -589,12 +589,17 @@ export class CanonicalImports { // add: one import is one implementation, and this is that one again. return answer; } - // Still the definition the identity was stated about. A claimed object the - // provider went on to edit is a different implementation, and taking a - // fresh copy of it here would record the edited one under the revision - // that described the original. Asked before anything is recorded and - // before the window is spent, so a refusal leaves both untouched. - if (held.baseline === undefined || !stillDescribes(held.baseline, answer)) { + // Retained once before it is compared: the answer may run user-controlled + // machinery when read, so comparing it and then retaining it would leave + // a gap in which those two reads could describe different definitions. + // Asked before anything is recorded and before the window is spent, so a + // refusal leaves both untouched. + const copy = retain(answer); + if ( + held.baseline === undefined || + copy === undefined || + !stillDescribes(held.baseline, copy) + ) { throw new AnswerIdentityError( "this answer no longer describes the implementation its identity was stated about, so a " + "further import cannot be answered with it. One implementation states what it is " + @@ -607,7 +612,7 @@ export class CanonicalImports { if (this.#spent.get(installation)?.has(open) === true) { throw new AnswerIdentityError(SPENT_OPPORTUNITY); } - held.copies.set(open, retain(answer)); + held.copies.set(open, copy); this.#spend(installation, open); return answer; } diff --git a/packages/core/tests/answer-identity.test.ts b/packages/core/tests/answer-identity.test.ts index cfdb56d37..b273d7a23 100644 --- a/packages/core/tests/answer-identity.test.ts +++ b/packages/core/tests/answer-identity.test.ts @@ -1135,6 +1135,59 @@ describe("Tier PA10c — one definition answering more than one import", () => { expect(imports.identify(first, shared)?.identity).toEqual(IDENTITY); }); + it("PA10c: reuse cannot substitute between comparison and retention", function* () { + const imports = owner(); + const provider = imports.provider(ORIGIN); + const here = yield* useScope(); + const reads: string[] = []; + const shared = new Proxy(answer(), { + get(target, key, receiver) { + if (key !== "name") { + return Reflect.get(target, key, receiver); + } + reads.push(key); + return reads.length === 1 ? "Open" : "Substituted"; + }, + getOwnPropertyDescriptor(target, key) { + const descriptor = Reflect.getOwnPropertyDescriptor(target, key); + if (key !== "name" || descriptor === undefined || !("value" in descriptor)) { + return descriptor; + } + return { ...descriptor, value: reads.length < 2 ? "Open" : "Substituted" }; + }, + }); + + const first = resolving( + imports, + "Open", + (resolution) => { + asking(provider, "Open", (request) => request.claim(shared, OPEN), here); + return resolution; + }, + here, + ); + expect(imports.identify(first, shared)?.definition.name).toBe("Open"); + resolving( + imports, + "Open", + (resolution) => { + asking( + provider, + "Open", + (request) => { + expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + return undefined; + }, + here, + ); + expect(imports.identify(resolution, shared)).toBe(undefined); + }, + here, + ); + }); + it("PA10c: an edited definition cannot be claimed again, and identifies nowhere", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); From 1a87568744a578c40e61e54b274486aa7ad23963 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 12:27:43 -0400 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9A=A1=20Measure=20test=20weights=20at?= =?UTF-8?q?=201d317942?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The committed file was measured at dcc94680, before the rebase brought #857's changes onto this branch and before the reused-answer correction added its own row. Remeasured on the runner at the current head, so the shard balance is a measurement of this corpus rather than of an earlier one. The artifact is committed exactly as the run produced it: the file states which commit and which run it came from, and nothing here edits it. The installed shard counts are unchanged — 15 Deno, 10 Node, 5 Bun — and every applicable file still fits one of them. --- test-weights.json | 2136 ++++++++++++++++++++++----------------------- 1 file changed, 1068 insertions(+), 1068 deletions(-) diff --git a/test-weights.json b/test-weights.json index dcb46f621..1874ae498 100644 --- a/test-weights.json +++ b/test-weights.json @@ -1,8 +1,8 @@ { "version": 1, "source": { - "commit": "dcc9468073ad005a241e6990e513e08b4cfeec86", - "runUrl": "https://github.com/taras/executable.md/actions/runs/36508610515", + "commit": "1d317942eb24810816c172998c083033f5d1165b", + "runUrl": "https://github.com/taras/executable.md/actions/runs/36577302779", "attempt": 1, "runner": "ubuntu-latest", "deno": "deno 2.9.5 (stable, release, x86_64-unknown-linux-gnu)", @@ -11,1097 +11,1097 @@ }, "runtimes": { "deno": { - "packages/acp/tests/acceptance.test.ts": 4925, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 7995, - "packages/acp/tests/acpx-materialization.test.ts": 7998, - "packages/acp/tests/acpx-transient-env.test.ts": 1713, - "packages/acp/tests/adapter-materialization.test.ts": 74834, - "packages/acp/tests/adapter-protocol.test.ts": 57230, - "packages/acp/tests/codex-surfaces.test.ts": 1705, - "packages/acp/tests/loaded-copy.test.ts": 4323, - "packages/acp/tests/native-launch.test.ts": 5024, - "packages/acp/tests/permission-bridge.test.ts": 3891, - "packages/acp/tests/provider.test.ts": 4931, - "packages/acp/tests/serial-queue.test.ts": 1469, - "packages/acp/tests/session-key.test.ts": 3734, - "packages/acp/tests/session-route.test.ts": 3924, - "packages/acp/tests/terminal-screen.test.ts": 1611, - "packages/cli/tests/agent-adapters.test.ts": 5252, - "packages/cli/tests/agent-cli.test.ts": 37916, - "packages/cli/tests/agent-config.test.ts": 3446, - "packages/cli/tests/agent-options-cli.test.ts": 15255, - "packages/cli/tests/agent-options.test.ts": 3457, - "packages/cli/tests/agent-session-coordinator.test.ts": 4141, - "packages/cli/tests/cli-help.test.ts": 20080, - "packages/cli/tests/command.test.ts": 10127, - "packages/cli/tests/compiled-upgrade.test.ts": 10098, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 8406, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 117411, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 7894, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 11311, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 9687, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 14586, - "packages/cli/tests/evaluate-component.test.ts": 11213, - "packages/cli/tests/evaluate-workflow.test.ts": 5148, - "packages/cli/tests/fetch-cli.test.ts": 3710, - "packages/cli/tests/file-stream.test.ts": 1695, - "packages/cli/tests/github-zero-effect.test.ts": 6789, - "packages/cli/tests/inline-cli.test.ts": 32124, - "packages/cli/tests/launch-timeout.test.ts": 11544, - "packages/cli/tests/packaged-document.test.ts": 4560, - "packages/cli/tests/plan-args.test.ts": 1475, - "packages/cli/tests/plan-cli.test.ts": 98305, - "packages/cli/tests/plan-command-document.test.ts": 9251, - "packages/cli/tests/plan-component.test.ts": 11401, - "packages/cli/tests/plan-host-acts.test.ts": 5136, - "packages/cli/tests/plan.test.ts": 15053, - "packages/cli/tests/plugin-cli.test.ts": 39337, - "packages/cli/tests/plugin-host.test.ts": 5721, - "packages/cli/tests/plugin-modules.test.ts": 1491, - "packages/cli/tests/plugin-selection.test.ts": 1462, - "packages/cli/tests/process-retention.test.ts": 5320, - "packages/cli/tests/props-cli.test.ts": 29643, - "packages/cli/tests/props-schema.test.ts": 3853, - "packages/cli/tests/props-sources.test.ts": 2168, - "packages/cli/tests/pull-request-read-fork.test.ts": 6972, - "packages/cli/tests/repl-boundaries.test.ts": 7126, - "packages/cli/tests/repl-composition.test.ts": 1973, - "packages/cli/tests/repl-execution.test.ts": 5120, - "packages/cli/tests/repl-journey.test.ts": 20282, - "packages/cli/tests/repl-model.test.ts": 4895, - "packages/cli/tests/repl-route.test.ts": 4539, - "packages/cli/tests/repl-terminal.test.ts": 2802, - "packages/cli/tests/run-composition-deno.test.ts": 7553, - "packages/cli/tests/run-composition-nested.test.ts": 20306, - "packages/cli/tests/run-composition.test.ts": 6661, - "packages/cli/tests/run-deadline.test.ts": 8292, - "packages/cli/tests/run-profile.test.ts": 4093, - "packages/cli/tests/run-timeouts.test.ts": 12891, - "packages/cli/tests/secret-detection-cli.test.ts": 18908, - "packages/cli/tests/service-document.test.ts": 5084, - "packages/cli/tests/service-host.test.ts": 4967, - "packages/cli/tests/session-launch-cli.test.ts": 10611, - "packages/cli/tests/stdin-cli.test.ts": 35938, - "packages/cli/tests/stdout-delivery.test.ts": 1493, - "packages/cli/tests/syntax-cli.test.ts": 34967, - "packages/cli/tests/targets-cli.test.ts": 28017, - "packages/cli/tests/test-root-profile.test.ts": 7213, - "packages/cli/tests/test-target.test.ts": 36058, - "packages/cli/tests/testing-activation.test.ts": 4313, - "packages/cli/tests/testing-execution-host.test.ts": 54460, - "packages/cli/tests/upgrade-cli.test.ts": 20416, - "packages/cli/tests/upgrade-command-document.test.ts": 6837, - "packages/cli/tests/upgrade-output.test.ts": 4281, - "packages/cli/tests/value-root.test.ts": 17072, - "packages/cli/tests/verbose-component.test.ts": 4743, - "packages/cli/tests/workflow-agent-sessions.test.ts": 19759, - "packages/cli/tests/workflow-agent.test.ts": 15164, - "packages/cli/tests/workflow-cli.test.ts": 107469, - "packages/cli/tests/workflow-crash.test.ts": 79525, - "packages/cli/tests/workflow-declaration.test.ts": 4297, - "packages/cli/tests/workflow-export-publication.test.ts": 17082, - "packages/cli/tests/workflow-fetch.test.ts": 7813, - "packages/cli/tests/workflow-fork.test.ts": 82603, - "packages/cli/tests/workflow-host.test.ts": 14341, - "packages/cli/tests/workflow-inspection.test.ts": 114514, - "packages/cli/tests/workflow-installation.test.ts": 5789, - "packages/cli/tests/workflow-lifecycle-control.test.ts": 20372, - "packages/cli/tests/workflow-retention.test.ts": 22615, - "packages/cli/tests/workflow-suspension.test.ts": 7433, - "packages/code-review-agent/tests/doctor.test.ts": 1483, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 1506, - "packages/code-review-agent/tests/parse-diff.test.ts": 1487, - "packages/code-review-agent/tests/parse-doctor.test.ts": 3784, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 1447, - "packages/code-review-agent/tests/policy.test.ts": 1472, - "packages/core/tests/agent-api.test.ts": 1504, - "packages/core/tests/agent-components.test.ts": 4337, - "packages/core/tests/agent-function-components.test.ts": 5875, - "packages/core/tests/agent-session-launch.test.ts": 6159, - "packages/core/tests/agent-session-placement.test.ts": 1526, - "packages/core/tests/agent-session-use-loaded-copy.test.ts": 1561, - "packages/core/tests/agent-session-use.test.ts": 1513, - "packages/core/tests/agent-stack.test.ts": 3957, - "packages/core/tests/all.test.ts": 4995, - "packages/core/tests/answer-identity.test.ts": 3439, - "packages/core/tests/answers-component.test.ts": 4532, - "packages/core/tests/answers-expansion-recursion.test.ts": 3632, - "packages/core/tests/capture-errors.test.ts": 3843, - "packages/core/tests/capture-props.test.ts": 3588, - "packages/core/tests/cli-journal.test.ts": 11694, - "packages/core/tests/code-block-component.test.ts": 4993, - "packages/core/tests/compiler-boundary.test.ts": 3665, - "packages/core/tests/component-api.test.ts": 3428, - "packages/core/tests/component-registration.test.ts": 4395, - "packages/core/tests/component-returns.test.ts": 4835, - "packages/core/tests/component-schema-conformance.test.ts": 3712, - "packages/core/tests/config-api.test.ts": 3754, - "packages/core/tests/construct-error-observation.test.ts": 3895, - "packages/core/tests/contextual-cwd.test.ts": 4888, - "packages/core/tests/daemon-integration.test.ts": 4429, - "packages/core/tests/daemon.test.ts": 3463, - "packages/core/tests/declared-markdown-component.test.ts": 5000, - "packages/core/tests/document-output-api.test.ts": 1444, - "packages/core/tests/document-target-execution.test.ts": 6297, - "packages/core/tests/document-targets.test.ts": 3785, - "packages/core/tests/document-validation.test.ts": 5134, - "packages/core/tests/documentation-index.test.ts": 3497, - "packages/core/tests/each.test.ts": 3754, - "packages/core/tests/elicit-component.test.ts": 4298, - "packages/core/tests/ephemeral-service.test.ts": 4165, - "packages/core/tests/eval-bindings.test.ts": 3708, - "packages/core/tests/eval-context.test.ts": 2106, - "packages/core/tests/eval-durable.test.ts": 3720, - "packages/core/tests/eval-error-mode.test.ts": 4028, - "packages/core/tests/eval-interpolate.test.ts": 1459, - "packages/core/tests/eval-middleware.test.ts": 3368, - "packages/core/tests/eval-persist.test.ts": 3852, - "packages/core/tests/eval-return.test.ts": 3733, - "packages/core/tests/eval-scope.test.ts": 3669, - "packages/core/tests/eval-timeout.test.ts": 3755, - "packages/core/tests/eval-transform.test.ts": 3409, - "packages/core/tests/evaluate-component.test.ts": 5494, - "packages/core/tests/evaluate-loaded-copy.test.ts": 3783, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 3875, - "packages/core/tests/evaluation-profile.test.ts": 3560, - "packages/core/tests/exec-timeout.test.ts": 3750, - "packages/core/tests/execute.test.ts": 4289, - "packages/core/tests/execution-protocol.test.ts": 4958, - "packages/core/tests/expand.test.ts": 4424, - "packages/core/tests/expansion-identity.test.ts": 4301, - "packages/core/tests/expansion-metadata.test.ts": 3646, - "packages/core/tests/expression-props.test.ts": 4171, - "packages/core/tests/fail-component.test.ts": 3894, - "packages/core/tests/failure-printing.test.ts": 3859, - "packages/core/tests/fatal-cause.test.ts": 3522, - "packages/core/tests/fetch-component.test.ts": 5018, - "packages/core/tests/file-component.test.ts": 5506, - "packages/core/tests/file-delete-component.test.ts": 3871, - "packages/core/tests/files-fatal.test.ts": 4581, - "packages/core/tests/foreground-exec.test.ts": 4627, - "packages/core/tests/frontmatter.test.ts": 3367, - "packages/core/tests/function-components.test.ts": 4255, - "packages/core/tests/generated-composition.test.ts": 4234, - "packages/core/tests/generated-xmd.test.ts": 5482, - "packages/core/tests/glob-api.test.ts": 1818, - "packages/core/tests/glob-component.test.ts": 4359, - "packages/core/tests/guarded-journal.test.ts": 3714, - "packages/core/tests/has-content.test.ts": 3560, - "packages/core/tests/heal.test.ts": 3600, - "packages/core/tests/if.test.ts": 4203, - "packages/core/tests/inline-root.test.ts": 3775, - "packages/core/tests/invocation-failures.test.ts": 3453, - "packages/core/tests/invocation-identity.test.ts": 4137, - "packages/core/tests/invocation-scope.test.ts": 3835, - "packages/core/tests/journal-source-position.test.ts": 3927, - "packages/core/tests/json-component.test.ts": 3940, - "packages/core/tests/json.test.ts": 3355, - "packages/core/tests/let.test.ts": 3782, - "packages/core/tests/loaded-copy-files.test.ts": 3672, - "packages/core/tests/loop.test.ts": 4503, - "packages/core/tests/named-slots.test.ts": 4522, - "packages/core/tests/output-error-mode.test.ts": 4677, - "packages/core/tests/output-normalize.test.ts": 1484, - "packages/core/tests/output-terminal.test.ts": 1582, - "packages/core/tests/parse-components.test.ts": 3809, - "packages/core/tests/plan-response.test.ts": 1476, - "packages/core/tests/plugin-api.test.ts": 3345, - "packages/core/tests/plugin.test.ts": 3524, - "packages/core/tests/props-binding.test.ts": 3867, - "packages/core/tests/protected-content.test.ts": 3323, - "packages/core/tests/registered-printed-errors.test.ts": 3509, - "packages/core/tests/replay-stream.test.ts": 1445, - "packages/core/tests/retain.test.ts": 3769, - "packages/core/tests/root-composition.test.ts": 3791, - "packages/core/tests/root-props.test.ts": 3881, - "packages/core/tests/root-provider.test.ts": 3844, - "packages/core/tests/sample-component.test.ts": 4527, - "packages/core/tests/scanner.test.ts": 3402, - "packages/core/tests/scope-local.test.ts": 1438, - "packages/core/tests/secret-detection.test.ts": 4477, - "packages/core/tests/secret-files.test.ts": 1909, - "packages/core/tests/secret-rules.test.ts": 2000, - "packages/core/tests/secret-scanner-baseline.test.ts": 1644, - "packages/core/tests/secret-scanner.test.ts": 1821, - "packages/core/tests/source-position.test.ts": 3590, - "packages/core/tests/state-ownership.test.ts": 3629, - "packages/core/tests/streaming-emission.test.ts": 3670, - "packages/core/tests/switch.test.ts": 4235, - "packages/core/tests/syntax-catalog.test.ts": 4262, - "packages/core/tests/syntax-component.test.ts": 4890, - "packages/core/tests/syntax-loaded-copy.test.ts": 3764, - "packages/core/tests/temp-dir.test.ts": 6150, - "packages/core/tests/temp-file-compiler.test.ts": 2119, - "packages/core/tests/text-interpolation.test.ts": 3553, - "packages/core/tests/try-content.test.ts": 3553, - "packages/core/tests/unused-in-diff.test.ts": 3788, - "packages/core/tests/validate.test.ts": 3555, - "packages/core/tests/validation-integration.test.ts": 3660, - "packages/core/tests/workflow-component-bundle.test.ts": 3893, - "packages/durable-streams/tests/context.test.ts": 1692, - "packages/durable-streams/tests/deterministic-id.test.ts": 1744, - "packages/durable-streams/tests/divergence-api.test.ts": 1737, - "packages/durable-streams/tests/divergence.test.ts": 1752, - "packages/durable-streams/tests/durable-each.test.ts": 1745, - "packages/durable-streams/tests/durable-position.test.ts": 1720, - "packages/durable-streams/tests/durable-run.test.ts": 1743, - "packages/durable-streams/tests/ephemeral.test.ts": 1734, - "packages/durable-streams/tests/fail-stop.test.ts": 1754, - "packages/durable-streams/tests/guard-stream.test.ts": 1794, - "packages/durable-streams/tests/live-coordinator.test.ts": 1727, - "packages/durable-streams/tests/parse.test.ts": 1720, - "packages/durable-streams/tests/replay-guard.test.ts": 1818, - "packages/durable-streams/tests/replay-index.test.ts": 1568, - "packages/durable-streams/tests/retained.test.ts": 1549, - "packages/durable-streams/tests/serialize-event.test.ts": 1727, - "packages/durable-streams/tests/smoke.test.ts": 1683, - "packages/durable-streams/tests/structured-concurrency.test.ts": 1863, - "packages/durable-streams/tests/terminal-boundary.test.ts": 1788, - "packages/durable-streams/tests/types.test.ts": 1422, - "packages/git/tests/ambient-authentication.test.ts": 25973, - "packages/git/tests/api-entrypoint.test.ts": 4845, - "packages/git/tests/credential-helper.test.ts": 5733, - "packages/git/tests/git-add-crash.test.ts": 6743, - "packages/git/tests/git-add-durability.test.ts": 25647, - "packages/git/tests/git-add.test.ts": 34009, - "packages/git/tests/git-commit-crash.test.ts": 7034, - "packages/git/tests/git-commit-durability.test.ts": 33023, - "packages/git/tests/git-commit.test.ts": 39374, - "packages/git/tests/git-host-effect.test.ts": 8331, - "packages/git/tests/git-push-crash.test.ts": 9585, - "packages/git/tests/git-push-durability.test.ts": 42379, - "packages/git/tests/git-push.test.ts": 50838, - "packages/git/tests/git-switch-crash.test.ts": 6924, - "packages/git/tests/git-switch-durability.test.ts": 21197, - "packages/git/tests/git-switch.test.ts": 22021, - "packages/git/tests/git.test.ts": 4184, - "packages/git/tests/github-activation.test.ts": 5328, - "packages/git/tests/github-issues.test.ts": 4145, - "packages/git/tests/github-pull-requests.test.ts": 3858, - "packages/git/tests/github-workflow-activation.test.ts": 5653, - "packages/git/tests/issue-markdown.test.ts": 10532, - "packages/git/tests/issue-records.test.ts": 4030, - "packages/git/tests/materialization.test.ts": 4732, - "packages/git/tests/module-partition.test.ts": 4966, - "packages/git/tests/plugin.test.ts": 4448, - "packages/git/tests/provider-neutrality.test.ts": 3264, - "packages/git/tests/public-entrypoint.test.ts": 9495, - "packages/git/tests/pull-request-crash.test.ts": 7874, - "packages/git/tests/pull-request-durability.test.ts": 40608, - "packages/git/tests/pull-request-read.test.ts": 7639, - "packages/git/tests/pull-request-records.test.ts": 4056, - "packages/git/tests/pull-request.test.ts": 72293, - "packages/git/tests/repository-components.test.ts": 11986, - "packages/git/tests/repository-control-plane.test.ts": 10869, - "packages/git/tests/repository-materialization.test.ts": 7959, - "packages/git/tests/repository-replay.test.ts": 15095, - "packages/git/tests/repository-storage.test.ts": 18473, - "packages/git/tests/run-composition-ambient.test.ts": 12538, - "packages/git/tests/run-composition-lazy.test.ts": 5388, - "packages/git/tests/run-composition-managed.test.ts": 14429, - "packages/git/tests/run-composition-remote.test.ts": 15169, - "packages/git/tests/selection-authentication.test.ts": 1740, - "packages/git/tests/worktree-replay.test.ts": 6437, - "packages/runtime/tests/agent-session-coordinator.test.ts": 2058, - "packages/runtime/tests/duration.test.ts": 1501, - "packages/runtime/tests/executable-observer.test.ts": 1777, - "packages/runtime/tests/fetch.test.ts": 2269, - "packages/runtime/tests/fs.test.ts": 1645, - "packages/runtime/tests/host-files.test.ts": 2483, - "packages/runtime/tests/native-launcher.test.ts": 3862, - "packages/runtime/tests/process.test.ts": 1666, - "packages/runtime/tests/service.test.ts": 1749, - "packages/test-agent/tests/acp-server.test.ts": 1627, - "packages/test-agent/tests/behavior-engine.test.ts": 3995, - "packages/test-agent/tests/bridge.test.ts": 3494, - "packages/test-agent/tests/command-lazy.test.ts": 7610, - "packages/test-agent/tests/components.test.ts": 60295, - "packages/test-agent/tests/controller.test.ts": 2721, - "packages/test-agent/tests/cross-package-resolution.test.ts": 5710, - "packages/test-agent/tests/native-launch.test.ts": 29937, - "packages/test-agent/tests/net.test.ts": 1575, - "packages/test-agent/tests/profile.test.ts": 3789, - "packages/test-agent/tests/protocol.test.ts": 2329, - "packages/test-agent/tests/provider.test.ts": 4107, - "packages/test-agent/tests/public-api.test.ts": 4749, - "packages/test-agent/tests/route-slot.test.ts": 1490, - "packages/test-agent/tests/smoke.test.ts": 20543, - "packages/test-agent/tests/template.test.ts": 3826, - "packages/test-agent/tests/worker-lifecycle.test.ts": 13012, - "packages/test-support/tests/journal.test.ts": 1732, - "packages/testing/tests/agent-composition.test.ts": 4034, - "packages/testing/tests/assert-throws.test.ts": 5162, - "packages/testing/tests/assert.test.ts": 1486, - "packages/testing/tests/assertions.test.ts": 5692, - "packages/testing/tests/boundary-contract.test.ts": 4771, - "packages/testing/tests/cli.test.ts": 6526, - "packages/testing/tests/execution-harness.test.ts": 8297, - "packages/testing/tests/replay.test.ts": 5172, - "packages/testing/tests/smoke.test.ts": 5361, - "packages/testing/tests/test-component.test.ts": 5782, - "packages/testing/tests/testing-activation.test.ts": 5472, - "packages/testing/tests/testing-boundary.test.ts": 4399, - "packages/testing/tests/testing-mode.test.ts": 5887, - "packages/testing/tests/use-testing.test.ts": 4923, - "packages/web/tests/assets.test.ts": 1532, - "packages/web/tests/client-logic.test.ts": 1578, - "packages/web/tests/compile.test.ts": 4447, - "packages/web/tests/component.test.ts": 4966, - "packages/web/tests/declaration.test.ts": 4210, - "packages/web/tests/document.test.ts": 4478, - "packages/web/tests/elicitation.test.ts": 4214, - "packages/web/tests/live-form.test.ts": 4139, - "packages/web/tests/markdown.test.ts": 1655, - "packages/web/tests/opener.test.ts": 4102, - "packages/web/tests/page.test.ts": 1479, - "packages/web/tests/responder.test.ts": 4333, - "packages/web/tests/server-lifecycle.test.ts": 4222, - "packages/web/tests/server.test.ts": 4572, - "packages/workflow/tests/generated-agent-component.test.ts": 6318, - "packages/workflow/tests/generated-observations.test.ts": 3953, - "packages/workflow/tests/public-entrypoint.test.ts": 5740, - "packages/workflow/tests/retained-run.test.ts": 4766, - "packages/workflow/tests/service-denial.test.ts": 1762, - "packages/workflow/tests/workflow-agent-checkpoints.test.ts": 5617, - "packages/workflow/tests/workflow-agent-sessions.test.ts": 4708, - "packages/workflow/tests/workflow-bundle.test.ts": 4187, - "packages/workflow/tests/workflow-checkpoint.test.ts": 5776, - "packages/workflow/tests/workflow-definition.test.ts": 3985, - "packages/workflow/tests/workflow-export.test.ts": 7543, - "packages/workflow/tests/workflow-fork-source.test.ts": 4799, - "packages/workflow/tests/workflow-fork.test.ts": 3870, - "packages/workflow/tests/workflow-lifecycle-authority.test.ts": 5713, - "packages/workflow/tests/workflow-lifecycle-control.test.ts": 6316, - "packages/workflow/tests/workflow-lifecycle-inspection.test.ts": 10799, - "packages/workflow/tests/workflow-run-journal.test.ts": 6855, - "packages/workflow/tests/workflow-run-storage.test.ts": 7704, - "packages/workflow/tests/workflow-run.test.ts": 4700, - "packages/workflow/tests/workflow-suspension-answer.test.ts": 5603, - "packages/workflow/tests/workflow-suspension.test.ts": 5290, - "packages/workflow/tests/workspace-crash-recovery.test.ts": 7490, - "packages/workflow/tests/workspace-effect-loaded-copy.test.ts": 4826, - "packages/workflow/tests/workspace-effect-transaction.test.ts": 5492, - "packages/workflow/tests/workspace-effect.test.ts": 5507, - "packages/workflow/tests/workspace-files.test.ts": 11949, - "packages/workflow/tests/workspace-root-restoration.test.ts": 6304, - "packages/workflow/tests/workspace-root.test.ts": 4790, - "packages/workflow/tests/workspace-transaction.test.ts": 4830, - "packages/workflow/tests/xmd-artifact.test.ts": 6443, - "scripts/tests/acpx-vendor.test.ts": 2059, - "scripts/tests/adapter-distribution.test.ts": 4299, - "scripts/tests/adapter-npm-package.test.ts": 31286, - "scripts/tests/adapter-vendor.test.ts": 3839, - "scripts/tests/bootstrap-npm-package.test.ts": 10708, - "scripts/tests/build-npm.test.ts": 38333, - "scripts/tests/build-web-client.test.ts": 28856, - "scripts/tests/bump-version.test.ts": 1605, - "scripts/tests/changed-paths.test.ts": 1492, - "scripts/tests/ci-workflow.test.ts": 4623, - "scripts/tests/cli-npm-bin.test.ts": 235231, - "scripts/tests/cloudflare-dofs-vendor.test.ts": 4168, - "scripts/tests/consumer-cycle.test.ts": 1570, - "scripts/tests/documentation-validation.test.ts": 5983, - "scripts/tests/filesystem-contract-workflow.test.ts": 1481, - "scripts/tests/frozen-entry.test.ts": 8003, - "scripts/tests/jsr-consumer-documentation.test.ts": 17210, - "scripts/tests/main-green.test.ts": 1851, - "scripts/tests/main-health.test.ts": 1622, - "scripts/tests/measure-test-weights.test.ts": 1875, - "scripts/tests/no-module-scoped-registry.test.ts": 2272, - "scripts/tests/no-redundant-test-scope.test.ts": 6327, - "scripts/tests/no-sync-filesystem.test.ts": 6152, - "scripts/tests/no-yield-in-finally.test.ts": 2273, - "scripts/tests/oxlint-policy.test.ts": 11876, - "scripts/tests/packaged-document.test.ts": 1518, - "scripts/tests/prefer-effection-operation.test.ts": 7301, - "scripts/tests/prefer-effection-result.test.ts": 5520, - "scripts/tests/prepared-state.test.ts": 2569, - "scripts/tests/publish-workflow-generator.test.ts": 5856, - "scripts/tests/publish-workflow-membership.test.ts": 1621, - "scripts/tests/publishable-membership-agreement.test.ts": 3824, - "scripts/tests/readme-targets.test.ts": 18157, - "scripts/tests/release-targets.test.ts": 1554, - "scripts/tests/review-infrastructure.test.ts": 5782, - "scripts/tests/runtime-exclusions.test.ts": 1928, - "scripts/tests/runtime-tests.test.ts": 1618, - "scripts/tests/scope-bound-event-registration.test.ts": 6098, - "scripts/tests/shard-execution.test.ts": 11071, - "scripts/tests/staged-write.test.ts": 1517, - "scripts/tests/test-file-discovery.test.ts": 1744, - "scripts/tests/test-shards.test.ts": 1520, - "scripts/tests/test-weights.test.ts": 1760, - "scripts/tests/tracked.test.ts": 1487, - "scripts/tests/verify-adapter.test.ts": 7650, - "scripts/tests/verify-clean.test.ts": 1672, - "scripts/tests/verify-coordinator.test.ts": 1836, - "scripts/tests/version-lockstep.test.ts": 1652, - "scripts/tests/web-client-module.test.ts": 1508, - "scripts/tests/workspace.test.ts": 1468 + "packages/acp/tests/acceptance.test.ts": 5052, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 8265, + "packages/acp/tests/acpx-materialization.test.ts": 8084, + "packages/acp/tests/acpx-transient-env.test.ts": 1772, + "packages/acp/tests/adapter-materialization.test.ts": 76537, + "packages/acp/tests/adapter-protocol.test.ts": 60468, + "packages/acp/tests/codex-surfaces.test.ts": 1819, + "packages/acp/tests/loaded-copy.test.ts": 4625, + "packages/acp/tests/native-launch.test.ts": 5333, + "packages/acp/tests/permission-bridge.test.ts": 4193, + "packages/acp/tests/provider.test.ts": 5345, + "packages/acp/tests/serial-queue.test.ts": 1527, + "packages/acp/tests/session-key.test.ts": 4017, + "packages/acp/tests/session-route.test.ts": 4255, + "packages/acp/tests/terminal-screen.test.ts": 1693, + "packages/cli/tests/agent-adapters.test.ts": 5698, + "packages/cli/tests/agent-cli.test.ts": 37667, + "packages/cli/tests/agent-config.test.ts": 3713, + "packages/cli/tests/agent-options-cli.test.ts": 15490, + "packages/cli/tests/agent-options.test.ts": 3668, + "packages/cli/tests/agent-session-coordinator.test.ts": 4387, + "packages/cli/tests/cli-help.test.ts": 20250, + "packages/cli/tests/command.test.ts": 10303, + "packages/cli/tests/compiled-upgrade.test.ts": 10775, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 8964, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 119858, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 8472, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 12290, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 10519, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 15587, + "packages/cli/tests/evaluate-component.test.ts": 11840, + "packages/cli/tests/evaluate-workflow.test.ts": 5549, + "packages/cli/tests/fetch-cli.test.ts": 3840, + "packages/cli/tests/file-stream.test.ts": 1813, + "packages/cli/tests/github-zero-effect.test.ts": 7355, + "packages/cli/tests/inline-cli.test.ts": 33157, + "packages/cli/tests/launch-timeout.test.ts": 11665, + "packages/cli/tests/packaged-document.test.ts": 5100, + "packages/cli/tests/plan-args.test.ts": 1604, + "packages/cli/tests/plan-cli.test.ts": 99258, + "packages/cli/tests/plan-command-document.test.ts": 10015, + "packages/cli/tests/plan-component.test.ts": 12327, + "packages/cli/tests/plan-host-acts.test.ts": 5534, + "packages/cli/tests/plan.test.ts": 16548, + "packages/cli/tests/plugin-cli.test.ts": 41189, + "packages/cli/tests/plugin-host.test.ts": 6252, + "packages/cli/tests/plugin-modules.test.ts": 1573, + "packages/cli/tests/plugin-selection.test.ts": 1563, + "packages/cli/tests/process-retention.test.ts": 5369, + "packages/cli/tests/props-cli.test.ts": 30488, + "packages/cli/tests/props-schema.test.ts": 4164, + "packages/cli/tests/props-sources.test.ts": 2281, + "packages/cli/tests/pull-request-read-fork.test.ts": 7124, + "packages/cli/tests/repl-boundaries.test.ts": 7465, + "packages/cli/tests/repl-composition.test.ts": 2041, + "packages/cli/tests/repl-execution.test.ts": 5465, + "packages/cli/tests/repl-journey.test.ts": 20626, + "packages/cli/tests/repl-model.test.ts": 5262, + "packages/cli/tests/repl-route.test.ts": 4795, + "packages/cli/tests/repl-terminal.test.ts": 2918, + "packages/cli/tests/run-composition-deno.test.ts": 8040, + "packages/cli/tests/run-composition-nested.test.ts": 21027, + "packages/cli/tests/run-composition.test.ts": 7115, + "packages/cli/tests/run-deadline.test.ts": 8779, + "packages/cli/tests/run-profile.test.ts": 4429, + "packages/cli/tests/run-timeouts.test.ts": 13312, + "packages/cli/tests/secret-detection-cli.test.ts": 19647, + "packages/cli/tests/service-document.test.ts": 5296, + "packages/cli/tests/service-host.test.ts": 5176, + "packages/cli/tests/session-launch-cli.test.ts": 10798, + "packages/cli/tests/stdin-cli.test.ts": 37368, + "packages/cli/tests/stdout-delivery.test.ts": 1550, + "packages/cli/tests/syntax-cli.test.ts": 36390, + "packages/cli/tests/targets-cli.test.ts": 28754, + "packages/cli/tests/test-root-profile.test.ts": 7297, + "packages/cli/tests/test-target.test.ts": 37254, + "packages/cli/tests/testing-activation.test.ts": 4614, + "packages/cli/tests/testing-execution-host.test.ts": 57092, + "packages/cli/tests/upgrade-cli.test.ts": 21098, + "packages/cli/tests/upgrade-command-document.test.ts": 7460, + "packages/cli/tests/upgrade-output.test.ts": 4847, + "packages/cli/tests/value-root.test.ts": 17921, + "packages/cli/tests/verbose-component.test.ts": 5102, + "packages/cli/tests/workflow-agent-sessions.test.ts": 20280, + "packages/cli/tests/workflow-agent.test.ts": 16266, + "packages/cli/tests/workflow-cli.test.ts": 109626, + "packages/cli/tests/workflow-crash.test.ts": 81308, + "packages/cli/tests/workflow-declaration.test.ts": 4615, + "packages/cli/tests/workflow-export-publication.test.ts": 17473, + "packages/cli/tests/workflow-fetch.test.ts": 8201, + "packages/cli/tests/workflow-fork.test.ts": 85080, + "packages/cli/tests/workflow-host.test.ts": 14668, + "packages/cli/tests/workflow-inspection.test.ts": 115910, + "packages/cli/tests/workflow-installation.test.ts": 6162, + "packages/cli/tests/workflow-lifecycle-control.test.ts": 20775, + "packages/cli/tests/workflow-retention.test.ts": 23092, + "packages/cli/tests/workflow-suspension.test.ts": 8136, + "packages/code-review-agent/tests/doctor.test.ts": 1533, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 1611, + "packages/code-review-agent/tests/parse-diff.test.ts": 1601, + "packages/code-review-agent/tests/parse-doctor.test.ts": 4012, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 1540, + "packages/code-review-agent/tests/policy.test.ts": 1551, + "packages/core/tests/agent-api.test.ts": 1567, + "packages/core/tests/agent-components.test.ts": 4627, + "packages/core/tests/agent-function-components.test.ts": 6345, + "packages/core/tests/agent-session-launch.test.ts": 6716, + "packages/core/tests/agent-session-placement.test.ts": 1612, + "packages/core/tests/agent-session-use-loaded-copy.test.ts": 1674, + "packages/core/tests/agent-session-use.test.ts": 1583, + "packages/core/tests/agent-stack.test.ts": 4198, + "packages/core/tests/all.test.ts": 5454, + "packages/core/tests/answer-identity.test.ts": 3695, + "packages/core/tests/answers-component.test.ts": 4788, + "packages/core/tests/answers-expansion-recursion.test.ts": 3892, + "packages/core/tests/capture-errors.test.ts": 4191, + "packages/core/tests/capture-props.test.ts": 3892, + "packages/core/tests/cli-journal.test.ts": 12094, + "packages/core/tests/code-block-component.test.ts": 5375, + "packages/core/tests/compiler-boundary.test.ts": 3850, + "packages/core/tests/component-api.test.ts": 3541, + "packages/core/tests/component-registration.test.ts": 4641, + "packages/core/tests/component-returns.test.ts": 5098, + "packages/core/tests/component-schema-conformance.test.ts": 3949, + "packages/core/tests/config-api.test.ts": 4047, + "packages/core/tests/construct-error-observation.test.ts": 4317, + "packages/core/tests/contextual-cwd.test.ts": 5151, + "packages/core/tests/daemon-integration.test.ts": 4696, + "packages/core/tests/daemon.test.ts": 3692, + "packages/core/tests/declared-markdown-component.test.ts": 5313, + "packages/core/tests/document-output-api.test.ts": 1535, + "packages/core/tests/document-target-execution.test.ts": 6755, + "packages/core/tests/document-targets.test.ts": 4030, + "packages/core/tests/document-validation.test.ts": 5348, + "packages/core/tests/documentation-index.test.ts": 3766, + "packages/core/tests/each.test.ts": 4056, + "packages/core/tests/elicit-component.test.ts": 4571, + "packages/core/tests/ephemeral-service.test.ts": 4359, + "packages/core/tests/eval-bindings.test.ts": 3914, + "packages/core/tests/eval-context.test.ts": 2152, + "packages/core/tests/eval-durable.test.ts": 3942, + "packages/core/tests/eval-error-mode.test.ts": 4324, + "packages/core/tests/eval-interpolate.test.ts": 1501, + "packages/core/tests/eval-middleware.test.ts": 3588, + "packages/core/tests/eval-persist.test.ts": 4073, + "packages/core/tests/eval-return.test.ts": 3935, + "packages/core/tests/eval-scope.test.ts": 3898, + "packages/core/tests/eval-timeout.test.ts": 4012, + "packages/core/tests/eval-transform.test.ts": 3660, + "packages/core/tests/evaluate-component.test.ts": 5827, + "packages/core/tests/evaluate-loaded-copy.test.ts": 3994, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 4113, + "packages/core/tests/evaluation-profile.test.ts": 3779, + "packages/core/tests/exec-timeout.test.ts": 4022, + "packages/core/tests/execute.test.ts": 4458, + "packages/core/tests/execution-protocol.test.ts": 5301, + "packages/core/tests/expand.test.ts": 4673, + "packages/core/tests/expansion-identity.test.ts": 4548, + "packages/core/tests/expansion-metadata.test.ts": 3861, + "packages/core/tests/expression-props.test.ts": 4437, + "packages/core/tests/fail-component.test.ts": 4195, + "packages/core/tests/failure-printing.test.ts": 4156, + "packages/core/tests/fatal-cause.test.ts": 3759, + "packages/core/tests/fetch-component.test.ts": 5241, + "packages/core/tests/file-component.test.ts": 5891, + "packages/core/tests/file-delete-component.test.ts": 4132, + "packages/core/tests/files-fatal.test.ts": 4879, + "packages/core/tests/foreground-exec.test.ts": 4978, + "packages/core/tests/frontmatter.test.ts": 3609, + "packages/core/tests/function-components.test.ts": 4564, + "packages/core/tests/generated-composition.test.ts": 4502, + "packages/core/tests/generated-xmd.test.ts": 5865, + "packages/core/tests/glob-api.test.ts": 1870, + "packages/core/tests/glob-component.test.ts": 4612, + "packages/core/tests/guarded-journal.test.ts": 3953, + "packages/core/tests/has-content.test.ts": 3774, + "packages/core/tests/heal.test.ts": 3735, + "packages/core/tests/if.test.ts": 4420, + "packages/core/tests/inline-root.test.ts": 3999, + "packages/core/tests/invocation-failures.test.ts": 3708, + "packages/core/tests/invocation-identity.test.ts": 4385, + "packages/core/tests/invocation-scope.test.ts": 4060, + "packages/core/tests/journal-source-position.test.ts": 4210, + "packages/core/tests/json-component.test.ts": 4198, + "packages/core/tests/json.test.ts": 3686, + "packages/core/tests/let.test.ts": 4053, + "packages/core/tests/loaded-copy-files.test.ts": 3954, + "packages/core/tests/loop.test.ts": 4890, + "packages/core/tests/named-slots.test.ts": 4735, + "packages/core/tests/output-error-mode.test.ts": 5015, + "packages/core/tests/output-normalize.test.ts": 1529, + "packages/core/tests/output-terminal.test.ts": 1659, + "packages/core/tests/parse-components.test.ts": 4034, + "packages/core/tests/plan-response.test.ts": 1561, + "packages/core/tests/plugin-api.test.ts": 3606, + "packages/core/tests/plugin.test.ts": 3795, + "packages/core/tests/props-binding.test.ts": 4064, + "packages/core/tests/protected-content.test.ts": 3574, + "packages/core/tests/registered-printed-errors.test.ts": 3690, + "packages/core/tests/replay-stream.test.ts": 1506, + "packages/core/tests/retain.test.ts": 3951, + "packages/core/tests/root-composition.test.ts": 4078, + "packages/core/tests/root-props.test.ts": 4101, + "packages/core/tests/root-provider.test.ts": 4105, + "packages/core/tests/sample-component.test.ts": 4739, + "packages/core/tests/scanner.test.ts": 3611, + "packages/core/tests/scope-local.test.ts": 1522, + "packages/core/tests/secret-detection.test.ts": 4752, + "packages/core/tests/secret-files.test.ts": 2054, + "packages/core/tests/secret-rules.test.ts": 2065, + "packages/core/tests/secret-scanner-baseline.test.ts": 1712, + "packages/core/tests/secret-scanner.test.ts": 1894, + "packages/core/tests/source-position.test.ts": 3886, + "packages/core/tests/state-ownership.test.ts": 3992, + "packages/core/tests/streaming-emission.test.ts": 3859, + "packages/core/tests/switch.test.ts": 4486, + "packages/core/tests/syntax-catalog.test.ts": 4543, + "packages/core/tests/syntax-component.test.ts": 5165, + "packages/core/tests/syntax-loaded-copy.test.ts": 3999, + "packages/core/tests/temp-dir.test.ts": 6398, + "packages/core/tests/temp-file-compiler.test.ts": 2199, + "packages/core/tests/text-interpolation.test.ts": 3718, + "packages/core/tests/try-content.test.ts": 3770, + "packages/core/tests/unused-in-diff.test.ts": 4055, + "packages/core/tests/validate.test.ts": 3855, + "packages/core/tests/validation-integration.test.ts": 3878, + "packages/core/tests/workflow-component-bundle.test.ts": 4177, + "packages/durable-streams/tests/context.test.ts": 1758, + "packages/durable-streams/tests/deterministic-id.test.ts": 1837, + "packages/durable-streams/tests/divergence-api.test.ts": 1795, + "packages/durable-streams/tests/divergence.test.ts": 1842, + "packages/durable-streams/tests/durable-each.test.ts": 1825, + "packages/durable-streams/tests/durable-position.test.ts": 1826, + "packages/durable-streams/tests/durable-run.test.ts": 1865, + "packages/durable-streams/tests/ephemeral.test.ts": 1833, + "packages/durable-streams/tests/fail-stop.test.ts": 1867, + "packages/durable-streams/tests/guard-stream.test.ts": 1921, + "packages/durable-streams/tests/live-coordinator.test.ts": 1889, + "packages/durable-streams/tests/parse.test.ts": 1805, + "packages/durable-streams/tests/replay-guard.test.ts": 1904, + "packages/durable-streams/tests/replay-index.test.ts": 1648, + "packages/durable-streams/tests/retained.test.ts": 1659, + "packages/durable-streams/tests/serialize-event.test.ts": 1795, + "packages/durable-streams/tests/smoke.test.ts": 1755, + "packages/durable-streams/tests/structured-concurrency.test.ts": 1917, + "packages/durable-streams/tests/terminal-boundary.test.ts": 1849, + "packages/durable-streams/tests/types.test.ts": 1474, + "packages/git/tests/ambient-authentication.test.ts": 26920, + "packages/git/tests/api-entrypoint.test.ts": 5024, + "packages/git/tests/credential-helper.test.ts": 6150, + "packages/git/tests/git-add-crash.test.ts": 7101, + "packages/git/tests/git-add-durability.test.ts": 26659, + "packages/git/tests/git-add.test.ts": 36546, + "packages/git/tests/git-commit-crash.test.ts": 7525, + "packages/git/tests/git-commit-durability.test.ts": 35279, + "packages/git/tests/git-commit.test.ts": 41445, + "packages/git/tests/git-host-effect.test.ts": 8853, + "packages/git/tests/git-push-crash.test.ts": 10168, + "packages/git/tests/git-push-durability.test.ts": 44331, + "packages/git/tests/git-push.test.ts": 52468, + "packages/git/tests/git-switch-crash.test.ts": 7212, + "packages/git/tests/git-switch-durability.test.ts": 22671, + "packages/git/tests/git-switch.test.ts": 23633, + "packages/git/tests/git.test.ts": 4425, + "packages/git/tests/github-activation.test.ts": 5638, + "packages/git/tests/github-issues.test.ts": 4456, + "packages/git/tests/github-pull-requests.test.ts": 4028, + "packages/git/tests/github-workflow-activation.test.ts": 6072, + "packages/git/tests/issue-markdown.test.ts": 11597, + "packages/git/tests/issue-records.test.ts": 4345, + "packages/git/tests/materialization.test.ts": 5100, + "packages/git/tests/module-partition.test.ts": 5568, + "packages/git/tests/plugin.test.ts": 4922, + "packages/git/tests/provider-neutrality.test.ts": 3530, + "packages/git/tests/public-entrypoint.test.ts": 9609, + "packages/git/tests/pull-request-crash.test.ts": 8456, + "packages/git/tests/pull-request-durability.test.ts": 42879, + "packages/git/tests/pull-request-read.test.ts": 8248, + "packages/git/tests/pull-request-records.test.ts": 4297, + "packages/git/tests/pull-request.test.ts": 76370, + "packages/git/tests/repository-components.test.ts": 12989, + "packages/git/tests/repository-control-plane.test.ts": 11769, + "packages/git/tests/repository-materialization.test.ts": 8521, + "packages/git/tests/repository-replay.test.ts": 16218, + "packages/git/tests/repository-storage.test.ts": 19972, + "packages/git/tests/run-composition-ambient.test.ts": 13475, + "packages/git/tests/run-composition-lazy.test.ts": 5858, + "packages/git/tests/run-composition-managed.test.ts": 15234, + "packages/git/tests/run-composition-remote.test.ts": 15401, + "packages/git/tests/selection-authentication.test.ts": 1789, + "packages/git/tests/worktree-replay.test.ts": 6885, + "packages/runtime/tests/agent-session-coordinator.test.ts": 2147, + "packages/runtime/tests/duration.test.ts": 1526, + "packages/runtime/tests/executable-observer.test.ts": 1867, + "packages/runtime/tests/fetch.test.ts": 2341, + "packages/runtime/tests/fs.test.ts": 1744, + "packages/runtime/tests/host-files.test.ts": 2608, + "packages/runtime/tests/native-launcher.test.ts": 3932, + "packages/runtime/tests/process.test.ts": 1698, + "packages/runtime/tests/service.test.ts": 1878, + "packages/test-agent/tests/acp-server.test.ts": 1670, + "packages/test-agent/tests/behavior-engine.test.ts": 4244, + "packages/test-agent/tests/bridge.test.ts": 3685, + "packages/test-agent/tests/command-lazy.test.ts": 7878, + "packages/test-agent/tests/components.test.ts": 61379, + "packages/test-agent/tests/controller.test.ts": 2867, + "packages/test-agent/tests/cross-package-resolution.test.ts": 6126, + "packages/test-agent/tests/native-launch.test.ts": 30721, + "packages/test-agent/tests/net.test.ts": 1612, + "packages/test-agent/tests/profile.test.ts": 3973, + "packages/test-agent/tests/protocol.test.ts": 2381, + "packages/test-agent/tests/provider.test.ts": 4345, + "packages/test-agent/tests/public-api.test.ts": 5052, + "packages/test-agent/tests/route-slot.test.ts": 1545, + "packages/test-agent/tests/smoke.test.ts": 21015, + "packages/test-agent/tests/template.test.ts": 3946, + "packages/test-agent/tests/worker-lifecycle.test.ts": 13274, + "packages/test-support/tests/journal.test.ts": 1790, + "packages/testing/tests/agent-composition.test.ts": 4374, + "packages/testing/tests/assert-throws.test.ts": 5586, + "packages/testing/tests/assert.test.ts": 1535, + "packages/testing/tests/assertions.test.ts": 6102, + "packages/testing/tests/boundary-contract.test.ts": 4997, + "packages/testing/tests/cli.test.ts": 6740, + "packages/testing/tests/execution-harness.test.ts": 8986, + "packages/testing/tests/replay.test.ts": 5551, + "packages/testing/tests/smoke.test.ts": 5689, + "packages/testing/tests/test-component.test.ts": 6283, + "packages/testing/tests/testing-activation.test.ts": 5898, + "packages/testing/tests/testing-boundary.test.ts": 4710, + "packages/testing/tests/testing-mode.test.ts": 6244, + "packages/testing/tests/use-testing.test.ts": 5237, + "packages/web/tests/assets.test.ts": 1596, + "packages/web/tests/client-logic.test.ts": 1641, + "packages/web/tests/compile.test.ts": 4685, + "packages/web/tests/component.test.ts": 5161, + "packages/web/tests/declaration.test.ts": 4462, + "packages/web/tests/document.test.ts": 4704, + "packages/web/tests/elicitation.test.ts": 4446, + "packages/web/tests/live-form.test.ts": 4335, + "packages/web/tests/markdown.test.ts": 1739, + "packages/web/tests/opener.test.ts": 4387, + "packages/web/tests/page.test.ts": 1617, + "packages/web/tests/responder.test.ts": 4673, + "packages/web/tests/server-lifecycle.test.ts": 4609, + "packages/web/tests/server.test.ts": 4878, + "packages/workflow/tests/generated-agent-component.test.ts": 6951, + "packages/workflow/tests/generated-observations.test.ts": 4117, + "packages/workflow/tests/public-entrypoint.test.ts": 5937, + "packages/workflow/tests/retained-run.test.ts": 5062, + "packages/workflow/tests/service-denial.test.ts": 1840, + "packages/workflow/tests/workflow-agent-checkpoints.test.ts": 6196, + "packages/workflow/tests/workflow-agent-sessions.test.ts": 5043, + "packages/workflow/tests/workflow-bundle.test.ts": 4453, + "packages/workflow/tests/workflow-checkpoint.test.ts": 6455, + "packages/workflow/tests/workflow-definition.test.ts": 4303, + "packages/workflow/tests/workflow-export.test.ts": 8192, + "packages/workflow/tests/workflow-fork-source.test.ts": 5083, + "packages/workflow/tests/workflow-fork.test.ts": 4149, + "packages/workflow/tests/workflow-lifecycle-authority.test.ts": 6054, + "packages/workflow/tests/workflow-lifecycle-control.test.ts": 6620, + "packages/workflow/tests/workflow-lifecycle-inspection.test.ts": 11366, + "packages/workflow/tests/workflow-run-journal.test.ts": 7268, + "packages/workflow/tests/workflow-run-storage.test.ts": 8669, + "packages/workflow/tests/workflow-run.test.ts": 5002, + "packages/workflow/tests/workflow-suspension-answer.test.ts": 5957, + "packages/workflow/tests/workflow-suspension.test.ts": 5651, + "packages/workflow/tests/workspace-crash-recovery.test.ts": 7782, + "packages/workflow/tests/workspace-effect-loaded-copy.test.ts": 5088, + "packages/workflow/tests/workspace-effect-transaction.test.ts": 6058, + "packages/workflow/tests/workspace-effect.test.ts": 5885, + "packages/workflow/tests/workspace-files.test.ts": 12944, + "packages/workflow/tests/workspace-root-restoration.test.ts": 6768, + "packages/workflow/tests/workspace-root.test.ts": 5232, + "packages/workflow/tests/workspace-transaction.test.ts": 5253, + "packages/workflow/tests/xmd-artifact.test.ts": 7086, + "scripts/tests/acpx-vendor.test.ts": 2133, + "scripts/tests/adapter-distribution.test.ts": 4533, + "scripts/tests/adapter-npm-package.test.ts": 29375, + "scripts/tests/adapter-vendor.test.ts": 4164, + "scripts/tests/bootstrap-npm-package.test.ts": 11332, + "scripts/tests/build-npm.test.ts": 40632, + "scripts/tests/build-web-client.test.ts": 30546, + "scripts/tests/bump-version.test.ts": 1665, + "scripts/tests/changed-paths.test.ts": 1507, + "scripts/tests/ci-workflow.test.ts": 4789, + "scripts/tests/cli-npm-bin.test.ts": 254860, + "scripts/tests/cloudflare-dofs-vendor.test.ts": 4318, + "scripts/tests/consumer-cycle.test.ts": 1629, + "scripts/tests/documentation-validation.test.ts": 6250, + "scripts/tests/filesystem-contract-workflow.test.ts": 1587, + "scripts/tests/frozen-entry.test.ts": 8636, + "scripts/tests/jsr-consumer-documentation.test.ts": 18081, + "scripts/tests/main-green.test.ts": 1952, + "scripts/tests/main-health.test.ts": 1704, + "scripts/tests/measure-test-weights.test.ts": 1951, + "scripts/tests/no-module-scoped-registry.test.ts": 2386, + "scripts/tests/no-redundant-test-scope.test.ts": 6499, + "scripts/tests/no-sync-filesystem.test.ts": 6361, + "scripts/tests/no-yield-in-finally.test.ts": 2391, + "scripts/tests/oxlint-policy.test.ts": 12056, + "scripts/tests/packaged-document.test.ts": 1592, + "scripts/tests/prefer-effection-operation.test.ts": 7576, + "scripts/tests/prefer-effection-result.test.ts": 5674, + "scripts/tests/prepared-state.test.ts": 2741, + "scripts/tests/publish-workflow-generator.test.ts": 6106, + "scripts/tests/publish-workflow-membership.test.ts": 1724, + "scripts/tests/publishable-membership-agreement.test.ts": 4059, + "scripts/tests/readme-targets.test.ts": 18856, + "scripts/tests/release-targets.test.ts": 1661, + "scripts/tests/review-infrastructure.test.ts": 6247, + "scripts/tests/runtime-exclusions.test.ts": 2075, + "scripts/tests/runtime-tests.test.ts": 1699, + "scripts/tests/scope-bound-event-registration.test.ts": 6375, + "scripts/tests/shard-execution.test.ts": 11387, + "scripts/tests/staged-write.test.ts": 1543, + "scripts/tests/test-file-discovery.test.ts": 1781, + "scripts/tests/test-shards.test.ts": 1561, + "scripts/tests/test-weights.test.ts": 1863, + "scripts/tests/tracked.test.ts": 1526, + "scripts/tests/verify-adapter.test.ts": 7643, + "scripts/tests/verify-clean.test.ts": 1751, + "scripts/tests/verify-coordinator.test.ts": 1943, + "scripts/tests/version-lockstep.test.ts": 1743, + "scripts/tests/web-client-module.test.ts": 1573, + "scripts/tests/workspace.test.ts": 1528 }, "node": { - "packages/acp/tests/acceptance.test.ts": 2046, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4862, - "packages/acp/tests/acpx-materialization.test.ts": 7053, - "packages/acp/tests/acpx-transient-env.test.ts": 797, - "packages/acp/tests/adapter-materialization.test.ts": 72478, - "packages/acp/tests/adapter-protocol.test.ts": 53071, - "packages/acp/tests/codex-surfaces.test.ts": 651, - "packages/acp/tests/native-launch.test.ts": 2114, - "packages/acp/tests/permission-bridge.test.ts": 1198, - "packages/acp/tests/provider.test.ts": 2070, - "packages/acp/tests/serial-queue.test.ts": 495, - "packages/acp/tests/session-key.test.ts": 528, - "packages/acp/tests/terminal-screen.test.ts": 587, - "packages/cli/tests/agent-adapters.test.ts": 2345, - "packages/cli/tests/agent-cli.test.ts": 41155, - "packages/cli/tests/agent-config.test.ts": 476, - "packages/cli/tests/agent-options-cli.test.ts": 15462, - "packages/cli/tests/agent-options.test.ts": 485, - "packages/cli/tests/agent-session-coordinator.test.ts": 1338, - "packages/cli/tests/cli-help.test.ts": 39037, - "packages/cli/tests/command.test.ts": 14308, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 4025, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 166249, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 3423, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 9374, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 5704, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 17252, - "packages/cli/tests/evaluate-component.test.ts": 14552, - "packages/cli/tests/fetch-cli.test.ts": 4700, - "packages/cli/tests/file-stream.test.ts": 531, - "packages/cli/tests/inline-cli.test.ts": 64136, - "packages/cli/tests/launch-timeout.test.ts": 20549, - "packages/cli/tests/packaged-document.test.ts": 1523, - "packages/cli/tests/plan-args.test.ts": 504, - "packages/cli/tests/plan-cli.test.ts": 113225, - "packages/cli/tests/plan-command-document.test.ts": 7456, - "packages/cli/tests/plan-component.test.ts": 10180, - "packages/cli/tests/plan-host-acts.test.ts": 2225, - "packages/cli/tests/plan.test.ts": 14740, - "packages/cli/tests/plugin-cli.test.ts": 77902, - "packages/cli/tests/plugin-host.test.ts": 3066, - "packages/cli/tests/plugin-modules.test.ts": 490, - "packages/cli/tests/plugin-selection.test.ts": 507, - "packages/cli/tests/process-retention.test.ts": 4662, - "packages/cli/tests/props-cli.test.ts": 60420, - "packages/cli/tests/props-schema.test.ts": 1304, - "packages/cli/tests/props-sources.test.ts": 665, - "packages/cli/tests/repl-boundaries.test.ts": 2400, - "packages/cli/tests/repl-composition.test.ts": 707, - "packages/cli/tests/repl-execution.test.ts": 2771, - "packages/cli/tests/repl-journey.test.ts": 11026, - "packages/cli/tests/repl-model.test.ts": 2555, - "packages/cli/tests/repl-route.test.ts": 2148, - "packages/cli/tests/repl-terminal.test.ts": 1251, - "packages/cli/tests/run-composition.test.ts": 3845, - "packages/cli/tests/run-deadline.test.ts": 3575, - "packages/cli/tests/run-profile.test.ts": 1203, - "packages/cli/tests/run-timeouts.test.ts": 19546, - "packages/cli/tests/secret-detection-cli.test.ts": 35993, - "packages/cli/tests/service-document.test.ts": 2540, - "packages/cli/tests/service-host.test.ts": 2331, - "packages/cli/tests/session-launch-cli.test.ts": 10504, - "packages/cli/tests/stdin-cli.test.ts": 60273, - "packages/cli/tests/stdout-delivery.test.ts": 481, - "packages/cli/tests/syntax-cli.test.ts": 58954, - "packages/cli/tests/targets-cli.test.ts": 48955, - "packages/cli/tests/test-root-profile.test.ts": 6726, - "packages/cli/tests/test-target.test.ts": 70319, - "packages/cli/tests/testing-activation.test.ts": 1405, - "packages/cli/tests/testing-execution-host.test.ts": 86424, - "packages/cli/tests/upgrade-cli.test.ts": 44503, - "packages/cli/tests/upgrade-command-document.test.ts": 5111, - "packages/cli/tests/upgrade-output.test.ts": 1768, - "packages/cli/tests/value-root.test.ts": 29628, - "packages/cli/tests/verbose-component.test.ts": 1850, - "packages/cli/tests/workflow-declaration.test.ts": 1422, - "packages/cli/tests/workflow-host.test.ts": 10303, - "packages/code-review-agent/tests/doctor.test.ts": 474, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 509, - "packages/code-review-agent/tests/parse-diff.test.ts": 482, - "packages/code-review-agent/tests/parse-doctor.test.ts": 1127, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 473, - "packages/code-review-agent/tests/policy.test.ts": 491, - "packages/core/tests/agent-api.test.ts": 486, - "packages/core/tests/agent-components.test.ts": 1915, - "packages/core/tests/agent-function-components.test.ts": 3966, - "packages/core/tests/agent-session-launch.test.ts": 3938, - "packages/core/tests/agent-session-placement.test.ts": 476, - "packages/core/tests/agent-session-use.test.ts": 467, - "packages/core/tests/agent-stack.test.ts": 1449, - "packages/core/tests/all.test.ts": 2788, - "packages/core/tests/answer-identity.test.ts": 546, - "packages/core/tests/answers-component.test.ts": 2208, - "packages/core/tests/answers-expansion-recursion.test.ts": 927, - "packages/core/tests/capture-errors.test.ts": 1205, - "packages/core/tests/capture-props.test.ts": 953, - "packages/core/tests/cli-journal.test.ts": 20838, - "packages/core/tests/code-block-component.test.ts": 2893, - "packages/core/tests/compiler-boundary.test.ts": 1116, - "packages/core/tests/component-api.test.ts": 545, - "packages/core/tests/component-registration.test.ts": 1968, - "packages/core/tests/component-returns.test.ts": 2651, - "packages/core/tests/component-schema-conformance.test.ts": 1079, - "packages/core/tests/config-api.test.ts": 1220, - "packages/core/tests/construct-error-observation.test.ts": 1278, - "packages/core/tests/contextual-cwd.test.ts": 2405, - "packages/core/tests/daemon-integration.test.ts": 1844, - "packages/core/tests/daemon.test.ts": 548, - "packages/core/tests/declared-markdown-component.test.ts": 2971, - "packages/core/tests/document-output-api.test.ts": 496, - "packages/core/tests/document-target-execution.test.ts": 4299, - "packages/core/tests/document-targets.test.ts": 1149, - "packages/core/tests/document-validation.test.ts": 2819, - "packages/core/tests/documentation-index.test.ts": 820, - "packages/core/tests/each.test.ts": 1222, - "packages/core/tests/elicit-component.test.ts": 1886, - "packages/core/tests/ephemeral-service.test.ts": 1715, - "packages/core/tests/eval-bindings.test.ts": 1176, - "packages/core/tests/eval-context.test.ts": 573, - "packages/core/tests/eval-durable.test.ts": 1250, - "packages/core/tests/eval-error-mode.test.ts": 1575, + "packages/acp/tests/acceptance.test.ts": 2110, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4869, + "packages/acp/tests/acpx-materialization.test.ts": 7089, + "packages/acp/tests/acpx-transient-env.test.ts": 828, + "packages/acp/tests/adapter-materialization.test.ts": 73589, + "packages/acp/tests/adapter-protocol.test.ts": 54177, + "packages/acp/tests/codex-surfaces.test.ts": 657, + "packages/acp/tests/native-launch.test.ts": 2222, + "packages/acp/tests/permission-bridge.test.ts": 1220, + "packages/acp/tests/provider.test.ts": 2161, + "packages/acp/tests/serial-queue.test.ts": 493, + "packages/acp/tests/session-key.test.ts": 549, + "packages/acp/tests/terminal-screen.test.ts": 611, + "packages/cli/tests/agent-adapters.test.ts": 2453, + "packages/cli/tests/agent-cli.test.ts": 43285, + "packages/cli/tests/agent-config.test.ts": 486, + "packages/cli/tests/agent-options-cli.test.ts": 16242, + "packages/cli/tests/agent-options.test.ts": 481, + "packages/cli/tests/agent-session-coordinator.test.ts": 1353, + "packages/cli/tests/cli-help.test.ts": 40747, + "packages/cli/tests/command.test.ts": 14935, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 4260, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 171781, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 3738, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 10122, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 6100, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 18177, + "packages/cli/tests/evaluate-component.test.ts": 15487, + "packages/cli/tests/fetch-cli.test.ts": 4949, + "packages/cli/tests/file-stream.test.ts": 533, + "packages/cli/tests/inline-cli.test.ts": 68083, + "packages/cli/tests/launch-timeout.test.ts": 20547, + "packages/cli/tests/packaged-document.test.ts": 1584, + "packages/cli/tests/plan-args.test.ts": 506, + "packages/cli/tests/plan-cli.test.ts": 119226, + "packages/cli/tests/plan-command-document.test.ts": 8084, + "packages/cli/tests/plan-component.test.ts": 11022, + "packages/cli/tests/plan-host-acts.test.ts": 2346, + "packages/cli/tests/plan.test.ts": 15829, + "packages/cli/tests/plugin-cli.test.ts": 82240, + "packages/cli/tests/plugin-host.test.ts": 3281, + "packages/cli/tests/plugin-modules.test.ts": 505, + "packages/cli/tests/plugin-selection.test.ts": 512, + "packages/cli/tests/process-retention.test.ts": 4997, + "packages/cli/tests/props-cli.test.ts": 63707, + "packages/cli/tests/props-schema.test.ts": 1350, + "packages/cli/tests/props-sources.test.ts": 683, + "packages/cli/tests/repl-boundaries.test.ts": 2529, + "packages/cli/tests/repl-composition.test.ts": 751, + "packages/cli/tests/repl-execution.test.ts": 2941, + "packages/cli/tests/repl-journey.test.ts": 11042, + "packages/cli/tests/repl-model.test.ts": 2778, + "packages/cli/tests/repl-route.test.ts": 2307, + "packages/cli/tests/repl-terminal.test.ts": 1256, + "packages/cli/tests/run-composition.test.ts": 4152, + "packages/cli/tests/run-deadline.test.ts": 3685, + "packages/cli/tests/run-profile.test.ts": 1253, + "packages/cli/tests/run-timeouts.test.ts": 20254, + "packages/cli/tests/secret-detection-cli.test.ts": 37931, + "packages/cli/tests/service-document.test.ts": 2565, + "packages/cli/tests/service-host.test.ts": 2347, + "packages/cli/tests/session-launch-cli.test.ts": 11044, + "packages/cli/tests/stdin-cli.test.ts": 63445, + "packages/cli/tests/stdout-delivery.test.ts": 493, + "packages/cli/tests/syntax-cli.test.ts": 62013, + "packages/cli/tests/targets-cli.test.ts": 51063, + "packages/cli/tests/test-root-profile.test.ts": 7125, + "packages/cli/tests/test-target.test.ts": 73776, + "packages/cli/tests/testing-activation.test.ts": 1497, + "packages/cli/tests/testing-execution-host.test.ts": 91050, + "packages/cli/tests/upgrade-cli.test.ts": 46673, + "packages/cli/tests/upgrade-command-document.test.ts": 5530, + "packages/cli/tests/upgrade-output.test.ts": 1845, + "packages/cli/tests/value-root.test.ts": 31600, + "packages/cli/tests/verbose-component.test.ts": 1940, + "packages/cli/tests/workflow-declaration.test.ts": 1449, + "packages/cli/tests/workflow-host.test.ts": 10859, + "packages/code-review-agent/tests/doctor.test.ts": 478, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 522, + "packages/code-review-agent/tests/parse-diff.test.ts": 517, + "packages/code-review-agent/tests/parse-doctor.test.ts": 1167, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 482, + "packages/code-review-agent/tests/policy.test.ts": 484, + "packages/core/tests/agent-api.test.ts": 493, + "packages/core/tests/agent-components.test.ts": 2035, + "packages/core/tests/agent-function-components.test.ts": 4189, + "packages/core/tests/agent-session-launch.test.ts": 4584, + "packages/core/tests/agent-session-placement.test.ts": 495, + "packages/core/tests/agent-session-use.test.ts": 483, + "packages/core/tests/agent-stack.test.ts": 1530, + "packages/core/tests/all.test.ts": 3001, + "packages/core/tests/answer-identity.test.ts": 578, + "packages/core/tests/answers-component.test.ts": 2373, + "packages/core/tests/answers-expansion-recursion.test.ts": 970, + "packages/core/tests/capture-errors.test.ts": 1288, + "packages/core/tests/capture-props.test.ts": 993, + "packages/core/tests/cli-journal.test.ts": 21990, + "packages/core/tests/code-block-component.test.ts": 3154, + "packages/core/tests/compiler-boundary.test.ts": 1162, + "packages/core/tests/component-api.test.ts": 557, + "packages/core/tests/component-registration.test.ts": 2067, + "packages/core/tests/component-returns.test.ts": 2830, + "packages/core/tests/component-schema-conformance.test.ts": 1092, + "packages/core/tests/config-api.test.ts": 1242, + "packages/core/tests/construct-error-observation.test.ts": 1361, + "packages/core/tests/contextual-cwd.test.ts": 2435, + "packages/core/tests/daemon-integration.test.ts": 1891, + "packages/core/tests/daemon.test.ts": 578, + "packages/core/tests/declared-markdown-component.test.ts": 3168, + "packages/core/tests/document-output-api.test.ts": 495, + "packages/core/tests/document-target-execution.test.ts": 4535, + "packages/core/tests/document-targets.test.ts": 1191, + "packages/core/tests/document-validation.test.ts": 3100, + "packages/core/tests/documentation-index.test.ts": 819, + "packages/core/tests/each.test.ts": 1263, + "packages/core/tests/elicit-component.test.ts": 1996, + "packages/core/tests/ephemeral-service.test.ts": 1791, + "packages/core/tests/eval-bindings.test.ts": 1271, + "packages/core/tests/eval-context.test.ts": 572, + "packages/core/tests/eval-durable.test.ts": 1276, + "packages/core/tests/eval-error-mode.test.ts": 1635, "packages/core/tests/eval-interpolate.test.ts": 502, - "packages/core/tests/eval-middleware.test.ts": 579, - "packages/core/tests/eval-persist.test.ts": 1346, - "packages/core/tests/eval-return.test.ts": 1233, - "packages/core/tests/eval-scope.test.ts": 1116, - "packages/core/tests/eval-timeout.test.ts": 1214, - "packages/core/tests/eval-transform.test.ts": 567, - "packages/core/tests/evaluate-component.test.ts": 3324, - "packages/core/tests/evaluate-loaded-copy.test.ts": 1291, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 1349, - "packages/core/tests/evaluation-profile.test.ts": 855, - "packages/core/tests/exec-timeout.test.ts": 1271, - "packages/core/tests/execute.test.ts": 1850, - "packages/core/tests/execution-protocol.test.ts": 2698, - "packages/core/tests/expand.test.ts": 1868, - "packages/core/tests/expansion-identity.test.ts": 1911, - "packages/core/tests/expansion-metadata.test.ts": 954, - "packages/core/tests/expression-props.test.ts": 1780, - "packages/core/tests/fail-component.test.ts": 1568, - "packages/core/tests/failure-printing.test.ts": 1390, - "packages/core/tests/fatal-cause.test.ts": 879, - "packages/core/tests/fetch-component.test.ts": 2722, - "packages/core/tests/file-component.test.ts": 3237, - "packages/core/tests/file-delete-component.test.ts": 1407, - "packages/core/tests/files-fatal.test.ts": 2279, - "packages/core/tests/foreground-exec.test.ts": 2227, - "packages/core/tests/frontmatter.test.ts": 532, - "packages/core/tests/function-components.test.ts": 1924, - "packages/core/tests/generated-composition.test.ts": 1905, - "packages/core/tests/generated-xmd.test.ts": 3319, - "packages/core/tests/glob-api.test.ts": 586, - "packages/core/tests/glob-component.test.ts": 1962, - "packages/core/tests/guarded-journal.test.ts": 1290, - "packages/core/tests/has-content.test.ts": 902, - "packages/core/tests/heal.test.ts": 911, - "packages/core/tests/if.test.ts": 1789, - "packages/core/tests/inline-root.test.ts": 1305, - "packages/core/tests/invocation-failures.test.ts": 587, - "packages/core/tests/invocation-identity.test.ts": 1708, - "packages/core/tests/invocation-scope.test.ts": 1149, - "packages/core/tests/journal-source-position.test.ts": 1386, - "packages/core/tests/json-component.test.ts": 1460, - "packages/core/tests/json.test.ts": 488, - "packages/core/tests/let.test.ts": 1250, - "packages/core/tests/loop.test.ts": 2136, - "packages/core/tests/named-slots.test.ts": 2180, - "packages/core/tests/output-error-mode.test.ts": 2395, - "packages/core/tests/output-normalize.test.ts": 500, - "packages/core/tests/output-terminal.test.ts": 687, - "packages/core/tests/parse-components.test.ts": 1357, - "packages/core/tests/plan-response.test.ts": 583, - "packages/core/tests/plugin-api.test.ts": 523, - "packages/core/tests/plugin.test.ts": 980, - "packages/core/tests/props-binding.test.ts": 1417, - "packages/core/tests/protected-content.test.ts": 527, - "packages/core/tests/registered-printed-errors.test.ts": 881, - "packages/core/tests/replay-stream.test.ts": 487, - "packages/core/tests/retain.test.ts": 1100, - "packages/core/tests/root-composition.test.ts": 1310, - "packages/core/tests/root-props.test.ts": 1395, - "packages/core/tests/root-provider.test.ts": 1293, - "packages/core/tests/sample-component.test.ts": 2221, - "packages/core/tests/scanner.test.ts": 567, + "packages/core/tests/eval-middleware.test.ts": 595, + "packages/core/tests/eval-persist.test.ts": 1380, + "packages/core/tests/eval-return.test.ts": 1313, + "packages/core/tests/eval-scope.test.ts": 1207, + "packages/core/tests/eval-timeout.test.ts": 1278, + "packages/core/tests/eval-transform.test.ts": 573, + "packages/core/tests/evaluate-component.test.ts": 3608, + "packages/core/tests/evaluate-loaded-copy.test.ts": 1339, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 1438, + "packages/core/tests/evaluation-profile.test.ts": 861, + "packages/core/tests/exec-timeout.test.ts": 1308, + "packages/core/tests/execute.test.ts": 1969, + "packages/core/tests/execution-protocol.test.ts": 2822, + "packages/core/tests/expand.test.ts": 1968, + "packages/core/tests/expansion-identity.test.ts": 2011, + "packages/core/tests/expansion-metadata.test.ts": 1010, + "packages/core/tests/expression-props.test.ts": 1863, + "packages/core/tests/fail-component.test.ts": 1631, + "packages/core/tests/failure-printing.test.ts": 1468, + "packages/core/tests/fatal-cause.test.ts": 890, + "packages/core/tests/fetch-component.test.ts": 2900, + "packages/core/tests/file-component.test.ts": 3333, + "packages/core/tests/file-delete-component.test.ts": 1461, + "packages/core/tests/files-fatal.test.ts": 2432, + "packages/core/tests/foreground-exec.test.ts": 2309, + "packages/core/tests/frontmatter.test.ts": 546, + "packages/core/tests/function-components.test.ts": 1982, + "packages/core/tests/generated-composition.test.ts": 2014, + "packages/core/tests/generated-xmd.test.ts": 3536, + "packages/core/tests/glob-api.test.ts": 625, + "packages/core/tests/glob-component.test.ts": 2058, + "packages/core/tests/guarded-journal.test.ts": 1304, + "packages/core/tests/has-content.test.ts": 924, + "packages/core/tests/heal.test.ts": 939, + "packages/core/tests/if.test.ts": 1837, + "packages/core/tests/inline-root.test.ts": 1327, + "packages/core/tests/invocation-failures.test.ts": 597, + "packages/core/tests/invocation-identity.test.ts": 1761, + "packages/core/tests/invocation-scope.test.ts": 1193, + "packages/core/tests/journal-source-position.test.ts": 1461, + "packages/core/tests/json-component.test.ts": 1541, + "packages/core/tests/json.test.ts": 499, + "packages/core/tests/let.test.ts": 1290, + "packages/core/tests/loop.test.ts": 2310, + "packages/core/tests/named-slots.test.ts": 2304, + "packages/core/tests/output-error-mode.test.ts": 2652, + "packages/core/tests/output-normalize.test.ts": 552, + "packages/core/tests/output-terminal.test.ts": 704, + "packages/core/tests/parse-components.test.ts": 1449, + "packages/core/tests/plan-response.test.ts": 609, + "packages/core/tests/plugin-api.test.ts": 532, + "packages/core/tests/plugin.test.ts": 1004, + "packages/core/tests/props-binding.test.ts": 1505, + "packages/core/tests/protected-content.test.ts": 551, + "packages/core/tests/registered-printed-errors.test.ts": 854, + "packages/core/tests/replay-stream.test.ts": 495, + "packages/core/tests/retain.test.ts": 1153, + "packages/core/tests/root-composition.test.ts": 1451, + "packages/core/tests/root-props.test.ts": 1490, + "packages/core/tests/root-provider.test.ts": 1343, + "packages/core/tests/sample-component.test.ts": 2330, + "packages/core/tests/scanner.test.ts": 590, "packages/core/tests/scope-local.test.ts": 489, - "packages/core/tests/secret-detection.test.ts": 2012, - "packages/core/tests/secret-files.test.ts": 741, - "packages/core/tests/secret-rules.test.ts": 808, - "packages/core/tests/secret-scanner-baseline.test.ts": 741, + "packages/core/tests/secret-detection.test.ts": 2104, + "packages/core/tests/secret-files.test.ts": 742, + "packages/core/tests/secret-rules.test.ts": 831, + "packages/core/tests/secret-scanner-baseline.test.ts": 747, "packages/core/tests/secret-scanner.test.ts": 701, - "packages/core/tests/source-position.test.ts": 1112, - "packages/core/tests/state-ownership.test.ts": 1191, - "packages/core/tests/streaming-emission.test.ts": 1134, - "packages/core/tests/switch.test.ts": 1800, - "packages/core/tests/syntax-catalog.test.ts": 1768, - "packages/core/tests/syntax-component.test.ts": 2531, - "packages/core/tests/temp-dir.test.ts": 3664, - "packages/core/tests/temp-file-compiler.test.ts": 537, - "packages/core/tests/text-interpolation.test.ts": 867, - "packages/core/tests/try-content.test.ts": 902, - "packages/core/tests/unused-in-diff.test.ts": 1304, + "packages/core/tests/source-position.test.ts": 1126, + "packages/core/tests/state-ownership.test.ts": 1193, + "packages/core/tests/streaming-emission.test.ts": 1174, + "packages/core/tests/switch.test.ts": 1868, + "packages/core/tests/syntax-catalog.test.ts": 1826, + "packages/core/tests/syntax-component.test.ts": 2697, + "packages/core/tests/temp-dir.test.ts": 3741, + "packages/core/tests/temp-file-compiler.test.ts": 555, + "packages/core/tests/text-interpolation.test.ts": 907, + "packages/core/tests/try-content.test.ts": 905, + "packages/core/tests/unused-in-diff.test.ts": 1388, "packages/core/tests/validate.test.ts": 795, - "packages/core/tests/validation-integration.test.ts": 1208, - "packages/core/tests/workflow-component-bundle.test.ts": 1471, - "packages/durable-streams/tests/context.test.ts": 499, - "packages/durable-streams/tests/deterministic-id.test.ts": 546, - "packages/durable-streams/tests/divergence-api.test.ts": 529, - "packages/durable-streams/tests/divergence.test.ts": 550, - "packages/durable-streams/tests/durable-each.test.ts": 580, - "packages/durable-streams/tests/durable-position.test.ts": 543, - "packages/durable-streams/tests/durable-run.test.ts": 552, - "packages/durable-streams/tests/ephemeral.test.ts": 532, - "packages/durable-streams/tests/fail-stop.test.ts": 602, - "packages/durable-streams/tests/guard-stream.test.ts": 662, - "packages/durable-streams/tests/live-coordinator.test.ts": 533, - "packages/durable-streams/tests/parse.test.ts": 569, - "packages/durable-streams/tests/replay-guard.test.ts": 575, - "packages/durable-streams/tests/replay-index.test.ts": 531, - "packages/durable-streams/tests/retained.test.ts": 530, - "packages/durable-streams/tests/serialize-event.test.ts": 521, + "packages/core/tests/validation-integration.test.ts": 1219, + "packages/core/tests/workflow-component-bundle.test.ts": 1577, + "packages/durable-streams/tests/context.test.ts": 528, + "packages/durable-streams/tests/deterministic-id.test.ts": 556, + "packages/durable-streams/tests/divergence-api.test.ts": 536, + "packages/durable-streams/tests/divergence.test.ts": 571, + "packages/durable-streams/tests/durable-each.test.ts": 567, + "packages/durable-streams/tests/durable-position.test.ts": 582, + "packages/durable-streams/tests/durable-run.test.ts": 566, + "packages/durable-streams/tests/ephemeral.test.ts": 551, + "packages/durable-streams/tests/fail-stop.test.ts": 586, + "packages/durable-streams/tests/guard-stream.test.ts": 619, + "packages/durable-streams/tests/live-coordinator.test.ts": 558, + "packages/durable-streams/tests/parse.test.ts": 586, + "packages/durable-streams/tests/replay-guard.test.ts": 587, + "packages/durable-streams/tests/replay-index.test.ts": 534, + "packages/durable-streams/tests/retained.test.ts": 535, + "packages/durable-streams/tests/serialize-event.test.ts": 536, "packages/durable-streams/tests/smoke.test.ts": 521, - "packages/durable-streams/tests/structured-concurrency.test.ts": 577, - "packages/durable-streams/tests/terminal-boundary.test.ts": 566, - "packages/durable-streams/tests/types.test.ts": 478, - "packages/git/tests/api-entrypoint.test.ts": 1273, - "packages/git/tests/git-host-effect.test.ts": 6666, - "packages/git/tests/git.test.ts": 1278, - "packages/git/tests/github-activation.test.ts": 1607, - "packages/git/tests/github-issues.test.ts": 1172, - "packages/git/tests/github-pull-requests.test.ts": 590, - "packages/git/tests/issue-markdown.test.ts": 9270, - "packages/git/tests/issue-records.test.ts": 1149, - "packages/git/tests/module-partition.test.ts": 2938, - "packages/git/tests/plugin.test.ts": 1664, - "packages/git/tests/provider-neutrality.test.ts": 2174, - "packages/git/tests/pull-request-records.test.ts": 1254, - "packages/git/tests/run-composition-lazy.test.ts": 1887, - "packages/git/tests/selection-authentication.test.ts": 492, - "packages/runtime/tests/duration.test.ts": 489, - "packages/runtime/tests/fetch.test.ts": 1100, - "packages/runtime/tests/fs.test.ts": 547, - "packages/runtime/tests/host-files.test.ts": 1249, - "packages/runtime/tests/native-launcher.test.ts": 2854, - "packages/runtime/tests/process.test.ts": 528, - "packages/runtime/tests/service.test.ts": 518, - "packages/test-agent/tests/acp-server.test.ts": 678, - "packages/test-agent/tests/behavior-engine.test.ts": 1531, - "packages/test-agent/tests/bridge.test.ts": 497, - "packages/test-agent/tests/command-lazy.test.ts": 6266, - "packages/test-agent/tests/components.test.ts": 102774, - "packages/test-agent/tests/controller.test.ts": 761, - "packages/test-agent/tests/cross-package-resolution.test.ts": 2749, - "packages/test-agent/tests/native-launch.test.ts": 52135, - "packages/test-agent/tests/net.test.ts": 582, - "packages/test-agent/tests/profile.test.ts": 1151, - "packages/test-agent/tests/protocol.test.ts": 580, - "packages/test-agent/tests/provider.test.ts": 1316, - "packages/test-agent/tests/public-api.test.ts": 1482, - "packages/test-agent/tests/route-slot.test.ts": 484, - "packages/test-agent/tests/smoke.test.ts": 27766, - "packages/test-agent/tests/template.test.ts": 1152, - "packages/test-agent/tests/worker-lifecycle.test.ts": 22654, - "packages/test-support/tests/journal.test.ts": 496, - "packages/testing/tests/agent-composition.test.ts": 1449, - "packages/testing/tests/assert-throws.test.ts": 2971, - "packages/testing/tests/assert.test.ts": 503, - "packages/testing/tests/assertions.test.ts": 3639, - "packages/testing/tests/boundary-contract.test.ts": 2389, - "packages/testing/tests/cli.test.ts": 10495, - "packages/testing/tests/execution-harness.test.ts": 6953, - "packages/testing/tests/replay.test.ts": 2885, - "packages/testing/tests/smoke.test.ts": 3072, - "packages/testing/tests/test-component.test.ts": 3838, - "packages/testing/tests/testing-activation.test.ts": 3222, - "packages/testing/tests/testing-boundary.test.ts": 1911, - "packages/testing/tests/testing-mode.test.ts": 3840, - "packages/testing/tests/use-testing.test.ts": 2610, - "packages/web/tests/assets.test.ts": 481, - "packages/web/tests/client-logic.test.ts": 526, - "packages/web/tests/compile.test.ts": 1866, - "packages/web/tests/component.test.ts": 2372, - "packages/web/tests/declaration.test.ts": 1607, - "packages/web/tests/document.test.ts": 1731, - "packages/web/tests/elicitation.test.ts": 1535, - "packages/web/tests/live-form.test.ts": 1443, - "packages/web/tests/markdown.test.ts": 739, - "packages/web/tests/opener.test.ts": 1428, - "packages/web/tests/page.test.ts": 497, - "packages/web/tests/responder.test.ts": 1747, - "packages/web/tests/server-lifecycle.test.ts": 1569, - "packages/web/tests/server.test.ts": 1985, - "packages/workflow/tests/generated-observations.test.ts": 1430, - "packages/workflow/tests/retained-run.test.ts": 2060, - "packages/workflow/tests/service-denial.test.ts": 511, - "packages/workflow/tests/workflow-bundle.test.ts": 1591, - "packages/workflow/tests/workflow-definition.test.ts": 1296, - "packages/workflow/tests/workflow-fork.test.ts": 1194, - "packages/workflow/tests/workflow-run.test.ts": 2017, - "packages/workflow/tests/workspace-effect.test.ts": 2865, - "packages/workflow/tests/xmd-artifact.test.ts": 3579, - "scripts/tests/adapter-vendor.test.ts": 702, - "scripts/tests/bootstrap-npm-package.test.ts": 7960, + "packages/durable-streams/tests/structured-concurrency.test.ts": 604, + "packages/durable-streams/tests/terminal-boundary.test.ts": 577, + "packages/durable-streams/tests/types.test.ts": 479, + "packages/git/tests/api-entrypoint.test.ts": 1319, + "packages/git/tests/git-host-effect.test.ts": 7178, + "packages/git/tests/git.test.ts": 1302, + "packages/git/tests/github-activation.test.ts": 1658, + "packages/git/tests/github-issues.test.ts": 1228, + "packages/git/tests/github-pull-requests.test.ts": 604, + "packages/git/tests/issue-markdown.test.ts": 9924, + "packages/git/tests/issue-records.test.ts": 1197, + "packages/git/tests/module-partition.test.ts": 3241, + "packages/git/tests/plugin.test.ts": 1731, + "packages/git/tests/provider-neutrality.test.ts": 2312, + "packages/git/tests/pull-request-records.test.ts": 1278, + "packages/git/tests/run-composition-lazy.test.ts": 1935, + "packages/git/tests/selection-authentication.test.ts": 499, + "packages/runtime/tests/duration.test.ts": 487, + "packages/runtime/tests/fetch.test.ts": 1112, + "packages/runtime/tests/fs.test.ts": 552, + "packages/runtime/tests/host-files.test.ts": 1286, + "packages/runtime/tests/native-launcher.test.ts": 2872, + "packages/runtime/tests/process.test.ts": 551, + "packages/runtime/tests/service.test.ts": 522, + "packages/test-agent/tests/acp-server.test.ts": 671, + "packages/test-agent/tests/behavior-engine.test.ts": 1586, + "packages/test-agent/tests/bridge.test.ts": 510, + "packages/test-agent/tests/command-lazy.test.ts": 6555, + "packages/test-agent/tests/components.test.ts": 107217, + "packages/test-agent/tests/controller.test.ts": 795, + "packages/test-agent/tests/cross-package-resolution.test.ts": 2908, + "packages/test-agent/tests/native-launch.test.ts": 54180, + "packages/test-agent/tests/net.test.ts": 588, + "packages/test-agent/tests/profile.test.ts": 1219, + "packages/test-agent/tests/protocol.test.ts": 577, + "packages/test-agent/tests/provider.test.ts": 1340, + "packages/test-agent/tests/public-api.test.ts": 1560, + "packages/test-agent/tests/route-slot.test.ts": 481, + "packages/test-agent/tests/smoke.test.ts": 28732, + "packages/test-agent/tests/template.test.ts": 1180, + "packages/test-agent/tests/worker-lifecycle.test.ts": 23743, + "packages/test-support/tests/journal.test.ts": 490, + "packages/testing/tests/agent-composition.test.ts": 1468, + "packages/testing/tests/assert-throws.test.ts": 3147, + "packages/testing/tests/assert.test.ts": 500, + "packages/testing/tests/assertions.test.ts": 3776, + "packages/testing/tests/boundary-contract.test.ts": 2504, + "packages/testing/tests/cli.test.ts": 10930, + "packages/testing/tests/execution-harness.test.ts": 7583, + "packages/testing/tests/replay.test.ts": 3031, + "packages/testing/tests/smoke.test.ts": 3238, + "packages/testing/tests/test-component.test.ts": 3984, + "packages/testing/tests/testing-activation.test.ts": 3433, + "packages/testing/tests/testing-boundary.test.ts": 2039, + "packages/testing/tests/testing-mode.test.ts": 4040, + "packages/testing/tests/use-testing.test.ts": 2862, + "packages/web/tests/assets.test.ts": 478, + "packages/web/tests/client-logic.test.ts": 543, + "packages/web/tests/compile.test.ts": 2041, + "packages/web/tests/component.test.ts": 2472, + "packages/web/tests/declaration.test.ts": 1651, + "packages/web/tests/document.test.ts": 1811, + "packages/web/tests/elicitation.test.ts": 1657, + "packages/web/tests/live-form.test.ts": 1487, + "packages/web/tests/markdown.test.ts": 686, + "packages/web/tests/opener.test.ts": 1477, + "packages/web/tests/page.test.ts": 480, + "packages/web/tests/responder.test.ts": 1832, + "packages/web/tests/server-lifecycle.test.ts": 1727, + "packages/web/tests/server.test.ts": 2061, + "packages/workflow/tests/generated-observations.test.ts": 1458, + "packages/workflow/tests/retained-run.test.ts": 2195, + "packages/workflow/tests/service-denial.test.ts": 508, + "packages/workflow/tests/workflow-bundle.test.ts": 1638, + "packages/workflow/tests/workflow-definition.test.ts": 1319, + "packages/workflow/tests/workflow-fork.test.ts": 1209, + "packages/workflow/tests/workflow-run.test.ts": 2081, + "packages/workflow/tests/workspace-effect.test.ts": 3067, + "packages/workflow/tests/xmd-artifact.test.ts": 3662, + "scripts/tests/adapter-vendor.test.ts": 721, + "scripts/tests/bootstrap-npm-package.test.ts": 8295, "scripts/tests/bump-version.test.ts": 611, - "scripts/tests/changed-paths.test.ts": 507, - "scripts/tests/ci-workflow.test.ts": 3499, - "scripts/tests/consumer-cycle.test.ts": 668, - "scripts/tests/filesystem-contract-workflow.test.ts": 575, - "scripts/tests/main-green.test.ts": 754, - "scripts/tests/main-health.test.ts": 599, - "scripts/tests/no-module-scoped-registry.test.ts": 1318, - "scripts/tests/no-redundant-test-scope.test.ts": 5258, - "scripts/tests/no-sync-filesystem.test.ts": 5442, - "scripts/tests/no-yield-in-finally.test.ts": 1290, - "scripts/tests/oxlint-policy.test.ts": 10787, - "scripts/tests/packaged-document.test.ts": 586, - "scripts/tests/prefer-effection-operation.test.ts": 6260, - "scripts/tests/prefer-effection-result.test.ts": 4481, - "scripts/tests/publish-workflow-membership.test.ts": 628, - "scripts/tests/review-infrastructure.test.ts": 3036, - "scripts/tests/runtime-exclusions.test.ts": 953, - "scripts/tests/runtime-tests.test.ts": 537, - "scripts/tests/scope-bound-event-registration.test.ts": 5310, - "scripts/tests/staged-write.test.ts": 528, - "scripts/tests/test-file-discovery.test.ts": 782, - "scripts/tests/test-shards.test.ts": 520, - "scripts/tests/test-weights.test.ts": 709, - "scripts/tests/tracked.test.ts": 574, + "scripts/tests/changed-paths.test.ts": 512, + "scripts/tests/ci-workflow.test.ts": 3638, + "scripts/tests/consumer-cycle.test.ts": 694, + "scripts/tests/filesystem-contract-workflow.test.ts": 587, + "scripts/tests/main-green.test.ts": 771, + "scripts/tests/main-health.test.ts": 619, + "scripts/tests/no-module-scoped-registry.test.ts": 1311, + "scripts/tests/no-redundant-test-scope.test.ts": 5343, + "scripts/tests/no-sync-filesystem.test.ts": 5664, + "scripts/tests/no-yield-in-finally.test.ts": 1317, + "scripts/tests/oxlint-policy.test.ts": 10912, + "scripts/tests/packaged-document.test.ts": 619, + "scripts/tests/prefer-effection-operation.test.ts": 6307, + "scripts/tests/prefer-effection-result.test.ts": 4550, + "scripts/tests/publish-workflow-membership.test.ts": 671, + "scripts/tests/review-infrastructure.test.ts": 3238, + "scripts/tests/runtime-exclusions.test.ts": 988, + "scripts/tests/runtime-tests.test.ts": 546, + "scripts/tests/scope-bound-event-registration.test.ts": 5495, + "scripts/tests/staged-write.test.ts": 537, + "scripts/tests/test-file-discovery.test.ts": 845, + "scripts/tests/test-shards.test.ts": 534, + "scripts/tests/test-weights.test.ts": 713, + "scripts/tests/tracked.test.ts": 542, "scripts/tests/verify-coordinator.test.ts": 717, - "scripts/tests/version-lockstep.test.ts": 688, - "scripts/tests/web-client-module.test.ts": 504, - "scripts/tests/workspace.test.ts": 498 + "scripts/tests/version-lockstep.test.ts": 698, + "scripts/tests/web-client-module.test.ts": 530, + "scripts/tests/workspace.test.ts": 506 }, "bun": { - "packages/acp/tests/acceptance.test.ts": 802, - "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4312, - "packages/acp/tests/acpx-materialization.test.ts": 6507, - "packages/acp/tests/acpx-transient-env.test.ts": 259, - "packages/acp/tests/adapter-materialization.test.ts": 69531, - "packages/acp/tests/adapter-protocol.test.ts": 52429, - "packages/acp/tests/codex-surfaces.test.ts": 154, - "packages/acp/tests/native-launch.test.ts": 1069, - "packages/acp/tests/permission-bridge.test.ts": 359, - "packages/acp/tests/provider.test.ts": 1114, - "packages/acp/tests/serial-queue.test.ts": 67, - "packages/acp/tests/session-key.test.ts": 64, - "packages/acp/tests/terminal-screen.test.ts": 90, - "packages/cli/tests/agent-adapters.test.ts": 1164, - "packages/cli/tests/agent-cli.test.ts": 20197, - "packages/cli/tests/agent-config.test.ts": 29, - "packages/cli/tests/agent-options-cli.test.ts": 7702, - "packages/cli/tests/agent-options.test.ts": 35, - "packages/cli/tests/agent-session-coordinator.test.ts": 393, - "packages/cli/tests/cli-help.test.ts": 15419, - "packages/cli/tests/command.test.ts": 7815, - "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 2837, - "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 103938, - "packages/cli/tests/document-suites/props/props-markdown.test.ts": 2210, - "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 4691, - "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 4448, - "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 8611, - "packages/cli/tests/evaluate-component.test.ts": 7498, - "packages/cli/tests/fetch-cli.test.ts": 2356, - "packages/cli/tests/file-stream.test.ts": 55, - "packages/cli/tests/inline-cli.test.ts": 30692, + "packages/acp/tests/acceptance.test.ts": 881, + "packages/acp/tests/acpx-checkpoint-meta.test.ts": 4309, + "packages/acp/tests/acpx-materialization.test.ts": 6504, + "packages/acp/tests/acpx-transient-env.test.ts": 255, + "packages/acp/tests/adapter-materialization.test.ts": 70550, + "packages/acp/tests/adapter-protocol.test.ts": 53397, + "packages/acp/tests/codex-surfaces.test.ts": 124, + "packages/acp/tests/native-launch.test.ts": 1004, + "packages/acp/tests/permission-bridge.test.ts": 367, + "packages/acp/tests/provider.test.ts": 1110, + "packages/acp/tests/serial-queue.test.ts": 65, + "packages/acp/tests/session-key.test.ts": 70, + "packages/acp/tests/terminal-screen.test.ts": 92, + "packages/cli/tests/agent-adapters.test.ts": 1152, + "packages/cli/tests/agent-cli.test.ts": 21790, + "packages/cli/tests/agent-config.test.ts": 30, + "packages/cli/tests/agent-options-cli.test.ts": 8164, + "packages/cli/tests/agent-options.test.ts": 33, + "packages/cli/tests/agent-session-coordinator.test.ts": 396, + "packages/cli/tests/cli-help.test.ts": 15775, + "packages/cli/tests/command.test.ts": 7938, + "packages/cli/tests/document-suites/inline/inline-markdown.test.ts": 2930, + "packages/cli/tests/document-suites/plan/plan-markdown.test.ts": 106383, + "packages/cli/tests/document-suites/props/props-markdown.test.ts": 2384, + "packages/cli/tests/document-suites/syntax/syntax-markdown.test.ts": 5311, + "packages/cli/tests/document-suites/targets/targets-markdown.test.ts": 5016, + "packages/cli/tests/document-suites/verbose/verbose-markdown.test.ts": 9107, + "packages/cli/tests/evaluate-component.test.ts": 8013, + "packages/cli/tests/fetch-cli.test.ts": 2379, + "packages/cli/tests/file-stream.test.ts": 56, + "packages/cli/tests/inline-cli.test.ts": 32942, "packages/cli/tests/launch-timeout.test.ts": 10096, - "packages/cli/tests/packaged-document.test.ts": 447, - "packages/cli/tests/plan-args.test.ts": 35, - "packages/cli/tests/plan-cli.test.ts": 58259, - "packages/cli/tests/plan-command-document.test.ts": 5727, - "packages/cli/tests/plan-component.test.ts": 9205, - "packages/cli/tests/plan-host-acts.test.ts": 1239, - "packages/cli/tests/plan.test.ts": 12979, - "packages/cli/tests/plugin-cli.test.ts": 39305, - "packages/cli/tests/plugin-host.test.ts": 2072, - "packages/cli/tests/plugin-modules.test.ts": 39, - "packages/cli/tests/plugin-selection.test.ts": 38, - "packages/cli/tests/process-retention.test.ts": 2532, - "packages/cli/tests/props-cli.test.ts": 29054, - "packages/cli/tests/props-schema.test.ts": 414, - "packages/cli/tests/props-sources.test.ts": 119, - "packages/cli/tests/repl-boundaries.test.ts": 1165, - "packages/cli/tests/repl-composition.test.ts": 138, - "packages/cli/tests/repl-execution.test.ts": 1868, - "packages/cli/tests/repl-journey.test.ts": 10385, - "packages/cli/tests/repl-model.test.ts": 1645, - "packages/cli/tests/repl-route.test.ts": 1217, - "packages/cli/tests/repl-terminal.test.ts": 881, - "packages/cli/tests/run-composition.test.ts": 2872, - "packages/cli/tests/run-deadline.test.ts": 2388, - "packages/cli/tests/run-profile.test.ts": 307, - "packages/cli/tests/run-timeouts.test.ts": 11100, - "packages/cli/tests/secret-detection-cli.test.ts": 17659, - "packages/cli/tests/service-document.test.ts": 1617, - "packages/cli/tests/service-host.test.ts": 1505, - "packages/cli/tests/session-launch-cli.test.ts": 5447, - "packages/cli/tests/stdin-cli.test.ts": 30139, - "packages/cli/tests/stdout-delivery.test.ts": 50, - "packages/cli/tests/syntax-cli.test.ts": 31494, - "packages/cli/tests/targets-cli.test.ts": 21382, - "packages/cli/tests/test-root-profile.test.ts": 3462, - "packages/cli/tests/test-target.test.ts": 34931, - "packages/cli/tests/testing-activation.test.ts": 538, - "packages/cli/tests/testing-execution-host.test.ts": 47835, - "packages/cli/tests/upgrade-cli.test.ts": 17841, - "packages/cli/tests/upgrade-command-document.test.ts": 3534, - "packages/cli/tests/upgrade-output.test.ts": 785, - "packages/cli/tests/value-root.test.ts": 15455, - "packages/cli/tests/verbose-component.test.ts": 781, - "packages/cli/tests/workflow-declaration.test.ts": 513, - "packages/cli/tests/workflow-host.test.ts": 4039, + "packages/cli/tests/packaged-document.test.ts": 465, + "packages/cli/tests/plan-args.test.ts": 39, + "packages/cli/tests/plan-cli.test.ts": 61713, + "packages/cli/tests/plan-command-document.test.ts": 5437, + "packages/cli/tests/plan-component.test.ts": 8825, + "packages/cli/tests/plan-host-acts.test.ts": 1167, + "packages/cli/tests/plan.test.ts": 12886, + "packages/cli/tests/plugin-cli.test.ts": 39744, + "packages/cli/tests/plugin-host.test.ts": 2006, + "packages/cli/tests/plugin-modules.test.ts": 36, + "packages/cli/tests/plugin-selection.test.ts": 36, + "packages/cli/tests/process-retention.test.ts": 2607, + "packages/cli/tests/props-cli.test.ts": 29136, + "packages/cli/tests/props-schema.test.ts": 422, + "packages/cli/tests/props-sources.test.ts": 128, + "packages/cli/tests/repl-boundaries.test.ts": 1229, + "packages/cli/tests/repl-composition.test.ts": 145, + "packages/cli/tests/repl-execution.test.ts": 1935, + "packages/cli/tests/repl-journey.test.ts": 10392, + "packages/cli/tests/repl-model.test.ts": 1784, + "packages/cli/tests/repl-route.test.ts": 1261, + "packages/cli/tests/repl-terminal.test.ts": 821, + "packages/cli/tests/run-composition.test.ts": 3038, + "packages/cli/tests/run-deadline.test.ts": 2382, + "packages/cli/tests/run-profile.test.ts": 312, + "packages/cli/tests/run-timeouts.test.ts": 11377, + "packages/cli/tests/secret-detection-cli.test.ts": 18381, + "packages/cli/tests/service-document.test.ts": 1532, + "packages/cli/tests/service-host.test.ts": 1390, + "packages/cli/tests/session-launch-cli.test.ts": 6066, + "packages/cli/tests/stdin-cli.test.ts": 31362, + "packages/cli/tests/stdout-delivery.test.ts": 52, + "packages/cli/tests/syntax-cli.test.ts": 33188, + "packages/cli/tests/targets-cli.test.ts": 21933, + "packages/cli/tests/test-root-profile.test.ts": 3814, + "packages/cli/tests/test-target.test.ts": 36435, + "packages/cli/tests/testing-activation.test.ts": 578, + "packages/cli/tests/testing-execution-host.test.ts": 49246, + "packages/cli/tests/upgrade-cli.test.ts": 18227, + "packages/cli/tests/upgrade-command-document.test.ts": 3569, + "packages/cli/tests/upgrade-output.test.ts": 831, + "packages/cli/tests/value-root.test.ts": 15949, + "packages/cli/tests/verbose-component.test.ts": 820, + "packages/cli/tests/workflow-declaration.test.ts": 538, + "packages/cli/tests/workflow-host.test.ts": 4406, "packages/code-review-agent/tests/doctor.test.ts": 30, - "packages/code-review-agent/tests/parse-diagnostics.test.ts": 63, - "packages/code-review-agent/tests/parse-diff.test.ts": 52, - "packages/code-review-agent/tests/parse-doctor.test.ts": 298, - "packages/code-review-agent/tests/parse-oxlint.test.ts": 29, - "packages/code-review-agent/tests/policy.test.ts": 32, - "packages/core/tests/agent-api.test.ts": 37, - "packages/core/tests/agent-components.test.ts": 1176, - "packages/core/tests/agent-function-components.test.ts": 3357, - "packages/core/tests/agent-session-launch.test.ts": 3472, + "packages/code-review-agent/tests/parse-diagnostics.test.ts": 39, + "packages/code-review-agent/tests/parse-diff.test.ts": 36, + "packages/code-review-agent/tests/parse-doctor.test.ts": 297, + "packages/code-review-agent/tests/parse-oxlint.test.ts": 30, + "packages/code-review-agent/tests/policy.test.ts": 34, + "packages/core/tests/agent-api.test.ts": 38, + "packages/core/tests/agent-components.test.ts": 1287, + "packages/core/tests/agent-function-components.test.ts": 3532, + "packages/core/tests/agent-session-launch.test.ts": 3433, "packages/core/tests/agent-session-placement.test.ts": 38, - "packages/core/tests/agent-session-use.test.ts": 33, - "packages/core/tests/agent-stack.test.ts": 699, - "packages/core/tests/all.test.ts": 2046, - "packages/core/tests/answer-identity.test.ts": 65, - "packages/core/tests/answers-component.test.ts": 1466, - "packages/core/tests/answers-expansion-recursion.test.ts": 307, - "packages/core/tests/capture-errors.test.ts": 573, - "packages/core/tests/capture-props.test.ts": 328, - "packages/core/tests/cli-journal.test.ts": 10236, - "packages/core/tests/code-block-component.test.ts": 2298, - "packages/core/tests/compiler-boundary.test.ts": 337, - "packages/core/tests/component-api.test.ts": 54, - "packages/core/tests/component-registration.test.ts": 1097, - "packages/core/tests/component-returns.test.ts": 1631, - "packages/core/tests/component-schema-conformance.test.ts": 544, - "packages/core/tests/config-api.test.ts": 340, - "packages/core/tests/construct-error-observation.test.ts": 697, - "packages/core/tests/contextual-cwd.test.ts": 1524, - "packages/core/tests/daemon-integration.test.ts": 1010, - "packages/core/tests/daemon.test.ts": 70, - "packages/core/tests/declared-markdown-component.test.ts": 2010, - "packages/core/tests/document-output-api.test.ts": 39, - "packages/core/tests/document-target-execution.test.ts": 3538, - "packages/core/tests/document-targets.test.ts": 428, - "packages/core/tests/document-validation.test.ts": 2141, - "packages/core/tests/documentation-index.test.ts": 166, - "packages/core/tests/each.test.ts": 417, - "packages/core/tests/elicit-component.test.ts": 1150, - "packages/core/tests/ephemeral-service.test.ts": 806, - "packages/core/tests/eval-bindings.test.ts": 390, - "packages/core/tests/eval-context.test.ts": 91, + "packages/core/tests/agent-session-use.test.ts": 47, + "packages/core/tests/agent-stack.test.ts": 785, + "packages/core/tests/all.test.ts": 2166, + "packages/core/tests/answer-identity.test.ts": 68, + "packages/core/tests/answers-component.test.ts": 1361, + "packages/core/tests/answers-expansion-recursion.test.ts": 327, + "packages/core/tests/capture-errors.test.ts": 569, + "packages/core/tests/capture-props.test.ts": 337, + "packages/core/tests/cli-journal.test.ts": 10559, + "packages/core/tests/code-block-component.test.ts": 2336, + "packages/core/tests/compiler-boundary.test.ts": 352, + "packages/core/tests/component-api.test.ts": 57, + "packages/core/tests/component-registration.test.ts": 1096, + "packages/core/tests/component-returns.test.ts": 1602, + "packages/core/tests/component-schema-conformance.test.ts": 553, + "packages/core/tests/config-api.test.ts": 339, + "packages/core/tests/construct-error-observation.test.ts": 710, + "packages/core/tests/contextual-cwd.test.ts": 1531, + "packages/core/tests/daemon-integration.test.ts": 1026, + "packages/core/tests/daemon.test.ts": 72, + "packages/core/tests/declared-markdown-component.test.ts": 1988, + "packages/core/tests/document-output-api.test.ts": 38, + "packages/core/tests/document-target-execution.test.ts": 3473, + "packages/core/tests/document-targets.test.ts": 407, + "packages/core/tests/document-validation.test.ts": 2083, + "packages/core/tests/documentation-index.test.ts": 167, + "packages/core/tests/each.test.ts": 421, + "packages/core/tests/elicit-component.test.ts": 1083, + "packages/core/tests/ephemeral-service.test.ts": 831, + "packages/core/tests/eval-bindings.test.ts": 401, + "packages/core/tests/eval-context.test.ts": 86, "packages/core/tests/eval-durable.test.ts": 426, - "packages/core/tests/eval-error-mode.test.ts": 683, - "packages/core/tests/eval-interpolate.test.ts": 40, - "packages/core/tests/eval-middleware.test.ts": 72, - "packages/core/tests/eval-persist.test.ts": 494, - "packages/core/tests/eval-return.test.ts": 418, - "packages/core/tests/eval-scope.test.ts": 319, - "packages/core/tests/eval-timeout.test.ts": 428, - "packages/core/tests/eval-transform.test.ts": 120, - "packages/core/tests/evaluate-component.test.ts": 2516, - "packages/core/tests/evaluate-loaded-copy.test.ts": 508, - "packages/core/tests/evaluate-provider-lifetime.test.ts": 579, + "packages/core/tests/eval-error-mode.test.ts": 690, + "packages/core/tests/eval-interpolate.test.ts": 39, + "packages/core/tests/eval-middleware.test.ts": 76, + "packages/core/tests/eval-persist.test.ts": 506, + "packages/core/tests/eval-return.test.ts": 424, + "packages/core/tests/eval-scope.test.ts": 334, + "packages/core/tests/eval-timeout.test.ts": 433, + "packages/core/tests/eval-transform.test.ts": 74, + "packages/core/tests/evaluate-component.test.ts": 2514, + "packages/core/tests/evaluate-loaded-copy.test.ts": 517, + "packages/core/tests/evaluate-provider-lifetime.test.ts": 576, "packages/core/tests/evaluation-profile.test.ts": 193, - "packages/core/tests/exec-timeout.test.ts": 484, - "packages/core/tests/execute.test.ts": 1057, - "packages/core/tests/execution-protocol.test.ts": 1568, - "packages/core/tests/expand.test.ts": 1254, - "packages/core/tests/expansion-identity.test.ts": 1244, - "packages/core/tests/expansion-metadata.test.ts": 356, - "packages/core/tests/expression-props.test.ts": 918, - "packages/core/tests/fail-component.test.ts": 783, - "packages/core/tests/failure-printing.test.ts": 738, - "packages/core/tests/fatal-cause.test.ts": 186, - "packages/core/tests/fetch-component.test.ts": 1866, - "packages/core/tests/file-component.test.ts": 2451, - "packages/core/tests/file-delete-component.test.ts": 656, - "packages/core/tests/files-fatal.test.ts": 1525, - "packages/core/tests/foreground-exec.test.ts": 1346, - "packages/core/tests/frontmatter.test.ts": 49, - "packages/core/tests/function-components.test.ts": 904, - "packages/core/tests/generated-composition.test.ts": 1169, - "packages/core/tests/generated-xmd.test.ts": 2477, - "packages/core/tests/glob-api.test.ts": 97, - "packages/core/tests/glob-component.test.ts": 1266, - "packages/core/tests/guarded-journal.test.ts": 437, - "packages/core/tests/has-content.test.ts": 277, - "packages/core/tests/heal.test.ts": 255, - "packages/core/tests/if.test.ts": 829, - "packages/core/tests/inline-root.test.ts": 513, - "packages/core/tests/invocation-failures.test.ts": 112, - "packages/core/tests/invocation-identity.test.ts": 860, - "packages/core/tests/invocation-scope.test.ts": 548, - "packages/core/tests/journal-source-position.test.ts": 614, - "packages/core/tests/json-component.test.ts": 2494, - "packages/core/tests/json.test.ts": 33, - "packages/core/tests/let.test.ts": 419, - "packages/core/tests/loop.test.ts": 1225, - "packages/core/tests/named-slots.test.ts": 1266, - "packages/core/tests/output-error-mode.test.ts": 1615, + "packages/core/tests/exec-timeout.test.ts": 502, + "packages/core/tests/execute.test.ts": 993, + "packages/core/tests/execution-protocol.test.ts": 1607, + "packages/core/tests/expand.test.ts": 1247, + "packages/core/tests/expansion-identity.test.ts": 1237, + "packages/core/tests/expansion-metadata.test.ts": 333, + "packages/core/tests/expression-props.test.ts": 891, + "packages/core/tests/fail-component.test.ts": 754, + "packages/core/tests/failure-printing.test.ts": 683, + "packages/core/tests/fatal-cause.test.ts": 188, + "packages/core/tests/fetch-component.test.ts": 1772, + "packages/core/tests/file-component.test.ts": 2425, + "packages/core/tests/file-delete-component.test.ts": 620, + "packages/core/tests/files-fatal.test.ts": 1468, + "packages/core/tests/foreground-exec.test.ts": 1236, + "packages/core/tests/frontmatter.test.ts": 48, + "packages/core/tests/function-components.test.ts": 912, + "packages/core/tests/generated-composition.test.ts": 1135, + "packages/core/tests/generated-xmd.test.ts": 2338, + "packages/core/tests/glob-api.test.ts": 99, + "packages/core/tests/glob-component.test.ts": 1236, + "packages/core/tests/guarded-journal.test.ts": 445, + "packages/core/tests/has-content.test.ts": 270, + "packages/core/tests/heal.test.ts": 266, + "packages/core/tests/if.test.ts": 827, + "packages/core/tests/inline-root.test.ts": 493, + "packages/core/tests/invocation-failures.test.ts": 104, + "packages/core/tests/invocation-identity.test.ts": 825, + "packages/core/tests/invocation-scope.test.ts": 550, + "packages/core/tests/journal-source-position.test.ts": 599, + "packages/core/tests/json-component.test.ts": 2337, + "packages/core/tests/json.test.ts": 35, + "packages/core/tests/let.test.ts": 423, + "packages/core/tests/loop.test.ts": 1241, + "packages/core/tests/named-slots.test.ts": 1274, + "packages/core/tests/output-error-mode.test.ts": 1565, "packages/core/tests/output-normalize.test.ts": 40, - "packages/core/tests/output-terminal.test.ts": 163, - "packages/core/tests/parse-components.test.ts": 693, - "packages/core/tests/plan-response.test.ts": 80, - "packages/core/tests/plugin-api.test.ts": 44, - "packages/core/tests/plugin.test.ts": 190, - "packages/core/tests/props-binding.test.ts": 557, - "packages/core/tests/protected-content.test.ts": 55, - "packages/core/tests/registered-printed-errors.test.ts": 202, - "packages/core/tests/replay-stream.test.ts": 37, - "packages/core/tests/retain.test.ts": 451, - "packages/core/tests/root-composition.test.ts": 563, - "packages/core/tests/root-props.test.ts": 588, - "packages/core/tests/root-provider.test.ts": 558, - "packages/core/tests/sample-component.test.ts": 1102, - "packages/core/tests/scanner.test.ts": 76, - "packages/core/tests/scope-local.test.ts": 34, - "packages/core/tests/secret-detection.test.ts": 1113, - "packages/core/tests/secret-files.test.ts": 131, - "packages/core/tests/secret-rules.test.ts": 152, - "packages/core/tests/secret-scanner-baseline.test.ts": 151, + "packages/core/tests/output-terminal.test.ts": 161, + "packages/core/tests/parse-components.test.ts": 664, + "packages/core/tests/plan-response.test.ts": 96, + "packages/core/tests/plugin-api.test.ts": 47, + "packages/core/tests/plugin.test.ts": 191, + "packages/core/tests/props-binding.test.ts": 533, + "packages/core/tests/protected-content.test.ts": 49, + "packages/core/tests/registered-printed-errors.test.ts": 214, + "packages/core/tests/replay-stream.test.ts": 35, + "packages/core/tests/retain.test.ts": 483, + "packages/core/tests/root-composition.test.ts": 572, + "packages/core/tests/root-props.test.ts": 569, + "packages/core/tests/root-provider.test.ts": 580, + "packages/core/tests/sample-component.test.ts": 1104, + "packages/core/tests/scanner.test.ts": 77, + "packages/core/tests/scope-local.test.ts": 35, + "packages/core/tests/secret-detection.test.ts": 1148, + "packages/core/tests/secret-files.test.ts": 128, + "packages/core/tests/secret-rules.test.ts": 150, + "packages/core/tests/secret-scanner-baseline.test.ts": 152, "packages/core/tests/secret-scanner.test.ts": 103, - "packages/core/tests/source-position.test.ts": 324, - "packages/core/tests/state-ownership.test.ts": 391, - "packages/core/tests/streaming-emission.test.ts": 309, - "packages/core/tests/switch.test.ts": 912, - "packages/core/tests/syntax-catalog.test.ts": 884, - "packages/core/tests/syntax-component.test.ts": 1735, - "packages/core/tests/temp-dir.test.ts": 2806, - "packages/core/tests/temp-file-compiler.test.ts": 81, - "packages/core/tests/text-interpolation.test.ts": 225, - "packages/core/tests/try-content.test.ts": 264, - "packages/core/tests/unused-in-diff.test.ts": 475, - "packages/core/tests/validate.test.ts": 300, - "packages/core/tests/validation-integration.test.ts": 361, - "packages/core/tests/workflow-component-bundle.test.ts": 701, - "packages/durable-streams/tests/context.test.ts": 37, - "packages/durable-streams/tests/deterministic-id.test.ts": 67, - "packages/durable-streams/tests/divergence-api.test.ts": 45, - "packages/durable-streams/tests/divergence.test.ts": 57, - "packages/durable-streams/tests/durable-each.test.ts": 63, - "packages/durable-streams/tests/durable-position.test.ts": 54, - "packages/durable-streams/tests/durable-run.test.ts": 64, - "packages/durable-streams/tests/ephemeral.test.ts": 61, + "packages/core/tests/source-position.test.ts": 376, + "packages/core/tests/state-ownership.test.ts": 404, + "packages/core/tests/streaming-emission.test.ts": 332, + "packages/core/tests/switch.test.ts": 817, + "packages/core/tests/syntax-catalog.test.ts": 894, + "packages/core/tests/syntax-component.test.ts": 1764, + "packages/core/tests/temp-dir.test.ts": 2800, + "packages/core/tests/temp-file-compiler.test.ts": 74, + "packages/core/tests/text-interpolation.test.ts": 229, + "packages/core/tests/try-content.test.ts": 270, + "packages/core/tests/unused-in-diff.test.ts": 502, + "packages/core/tests/validate.test.ts": 322, + "packages/core/tests/validation-integration.test.ts": 366, + "packages/core/tests/workflow-component-bundle.test.ts": 706, + "packages/durable-streams/tests/context.test.ts": 35, + "packages/durable-streams/tests/deterministic-id.test.ts": 68, + "packages/durable-streams/tests/divergence-api.test.ts": 46, + "packages/durable-streams/tests/divergence.test.ts": 56, + "packages/durable-streams/tests/durable-each.test.ts": 69, + "packages/durable-streams/tests/durable-position.test.ts": 58, + "packages/durable-streams/tests/durable-run.test.ts": 65, + "packages/durable-streams/tests/ephemeral.test.ts": 60, "packages/durable-streams/tests/fail-stop.test.ts": 73, - "packages/durable-streams/tests/guard-stream.test.ts": 99, - "packages/durable-streams/tests/live-coordinator.test.ts": 56, - "packages/durable-streams/tests/parse.test.ts": 50, - "packages/durable-streams/tests/replay-guard.test.ts": 71, - "packages/durable-streams/tests/replay-index.test.ts": 45, - "packages/durable-streams/tests/retained.test.ts": 63, - "packages/durable-streams/tests/serialize-event.test.ts": 83, - "packages/durable-streams/tests/smoke.test.ts": 34, - "packages/durable-streams/tests/structured-concurrency.test.ts": 88, - "packages/durable-streams/tests/terminal-boundary.test.ts": 75, - "packages/durable-streams/tests/types.test.ts": 29, - "packages/git/tests/api-entrypoint.test.ts": 297, - "packages/git/tests/git-host-effect.test.ts": 7018, - "packages/git/tests/git.test.ts": 414, - "packages/git/tests/github-activation.test.ts": 825, - "packages/git/tests/github-issues.test.ts": 335, - "packages/git/tests/github-pull-requests.test.ts": 88, - "packages/git/tests/issue-markdown.test.ts": 8832, - "packages/git/tests/issue-records.test.ts": 291, - "packages/git/tests/module-partition.test.ts": 1763, - "packages/git/tests/plugin.test.ts": 903, - "packages/git/tests/provider-neutrality.test.ts": 1061, - "packages/git/tests/pull-request-records.test.ts": 326, - "packages/git/tests/run-composition-lazy.test.ts": 824, - "packages/git/tests/selection-authentication.test.ts": 40, - "packages/runtime/tests/duration.test.ts": 33, - "packages/runtime/tests/fetch.test.ts": 629, - "packages/runtime/tests/fs.test.ts": 70, - "packages/runtime/tests/host-files.test.ts": 733, - "packages/runtime/tests/native-launcher.test.ts": 2442, - "packages/runtime/tests/process.test.ts": 89, + "packages/durable-streams/tests/guard-stream.test.ts": 109, + "packages/durable-streams/tests/live-coordinator.test.ts": 59, + "packages/durable-streams/tests/parse.test.ts": 51, + "packages/durable-streams/tests/replay-guard.test.ts": 70, + "packages/durable-streams/tests/replay-index.test.ts": 48, + "packages/durable-streams/tests/retained.test.ts": 44, + "packages/durable-streams/tests/serialize-event.test.ts": 41, + "packages/durable-streams/tests/smoke.test.ts": 33, + "packages/durable-streams/tests/structured-concurrency.test.ts": 94, + "packages/durable-streams/tests/terminal-boundary.test.ts": 77, + "packages/durable-streams/tests/types.test.ts": 30, + "packages/git/tests/api-entrypoint.test.ts": 306, + "packages/git/tests/git-host-effect.test.ts": 6749, + "packages/git/tests/git.test.ts": 376, + "packages/git/tests/github-activation.test.ts": 697, + "packages/git/tests/github-issues.test.ts": 317, + "packages/git/tests/github-pull-requests.test.ts": 100, + "packages/git/tests/issue-markdown.test.ts": 8692, + "packages/git/tests/issue-records.test.ts": 314, + "packages/git/tests/module-partition.test.ts": 1883, + "packages/git/tests/plugin.test.ts": 799, + "packages/git/tests/provider-neutrality.test.ts": 1090, + "packages/git/tests/pull-request-records.test.ts": 332, + "packages/git/tests/run-composition-lazy.test.ts": 785, + "packages/git/tests/selection-authentication.test.ts": 39, + "packages/runtime/tests/duration.test.ts": 30, + "packages/runtime/tests/fetch.test.ts": 620, + "packages/runtime/tests/fs.test.ts": 78, + "packages/runtime/tests/host-files.test.ts": 732, + "packages/runtime/tests/native-launcher.test.ts": 2404, + "packages/runtime/tests/process.test.ts": 82, "packages/runtime/tests/service.test.ts": 66, - "packages/test-agent/tests/acp-server.test.ts": 114, - "packages/test-agent/tests/behavior-engine.test.ts": 714, + "packages/test-agent/tests/acp-server.test.ts": 102, + "packages/test-agent/tests/behavior-engine.test.ts": 662, "packages/test-agent/tests/bridge.test.ts": 68, - "packages/test-agent/tests/command-lazy.test.ts": 3368, - "packages/test-agent/tests/components.test.ts": 52666, - "packages/test-agent/tests/controller.test.ts": 207, - "packages/test-agent/tests/cross-package-resolution.test.ts": 1852, - "packages/test-agent/tests/native-launch.test.ts": 24354, - "packages/test-agent/tests/net.test.ts": 104, - "packages/test-agent/tests/profile.test.ts": 306, - "packages/test-agent/tests/protocol.test.ts": 58, - "packages/test-agent/tests/provider.test.ts": 398, - "packages/test-agent/tests/public-api.test.ts": 466, - "packages/test-agent/tests/route-slot.test.ts": 58, - "packages/test-agent/tests/smoke.test.ts": 15428, - "packages/test-agent/tests/template.test.ts": 287, - "packages/test-agent/tests/worker-lifecycle.test.ts": 9194, + "packages/test-agent/tests/command-lazy.test.ts": 3306, + "packages/test-agent/tests/components.test.ts": 52683, + "packages/test-agent/tests/controller.test.ts": 197, + "packages/test-agent/tests/cross-package-resolution.test.ts": 1798, + "packages/test-agent/tests/native-launch.test.ts": 24490, + "packages/test-agent/tests/net.test.ts": 110, + "packages/test-agent/tests/profile.test.ts": 321, + "packages/test-agent/tests/protocol.test.ts": 61, + "packages/test-agent/tests/provider.test.ts": 405, + "packages/test-agent/tests/public-api.test.ts": 476, + "packages/test-agent/tests/route-slot.test.ts": 59, + "packages/test-agent/tests/smoke.test.ts": 15508, + "packages/test-agent/tests/template.test.ts": 295, + "packages/test-agent/tests/worker-lifecycle.test.ts": 9251, "packages/test-support/tests/journal.test.ts": 41, - "packages/testing/tests/agent-composition.test.ts": 606, - "packages/testing/tests/assert-throws.test.ts": 2229, - "packages/testing/tests/assert.test.ts": 57, - "packages/testing/tests/assertions.test.ts": 2955, - "packages/testing/tests/boundary-contract.test.ts": 1574, - "packages/testing/tests/cli.test.ts": 4937, - "packages/testing/tests/execution-harness.test.ts": 6752, - "packages/testing/tests/replay.test.ts": 2277, - "packages/testing/tests/smoke.test.ts": 1870, - "packages/testing/tests/test-component.test.ts": 2935, - "packages/testing/tests/testing-activation.test.ts": 2541, - "packages/testing/tests/testing-boundary.test.ts": 1079, - "packages/testing/tests/testing-mode.test.ts": 3038, - "packages/testing/tests/use-testing.test.ts": 1759, - "packages/web/tests/assets.test.ts": 44, - "packages/web/tests/client-logic.test.ts": 61, - "packages/web/tests/compile.test.ts": 925, - "packages/web/tests/component.test.ts": 1458, - "packages/web/tests/declaration.test.ts": 669, - "packages/web/tests/document.test.ts": 763, - "packages/web/tests/elicitation.test.ts": 544, - "packages/web/tests/live-form.test.ts": 500, - "packages/web/tests/markdown.test.ts": 135, - "packages/web/tests/opener.test.ts": 483, - "packages/web/tests/page.test.ts": 33, - "packages/web/tests/responder.test.ts": 837, - "packages/web/tests/server-lifecycle.test.ts": 621, + "packages/testing/tests/agent-composition.test.ts": 610, + "packages/testing/tests/assert-throws.test.ts": 2263, + "packages/testing/tests/assert.test.ts": 56, + "packages/testing/tests/assertions.test.ts": 2965, + "packages/testing/tests/boundary-contract.test.ts": 1659, + "packages/testing/tests/cli.test.ts": 4908, + "packages/testing/tests/execution-harness.test.ts": 6397, + "packages/testing/tests/replay.test.ts": 2206, + "packages/testing/tests/smoke.test.ts": 1784, + "packages/testing/tests/test-component.test.ts": 2982, + "packages/testing/tests/testing-activation.test.ts": 2597, + "packages/testing/tests/testing-boundary.test.ts": 1088, + "packages/testing/tests/testing-mode.test.ts": 3165, + "packages/testing/tests/use-testing.test.ts": 1880, + "packages/web/tests/assets.test.ts": 30, + "packages/web/tests/client-logic.test.ts": 37, + "packages/web/tests/compile.test.ts": 997, + "packages/web/tests/component.test.ts": 1441, + "packages/web/tests/declaration.test.ts": 649, + "packages/web/tests/document.test.ts": 791, + "packages/web/tests/elicitation.test.ts": 559, + "packages/web/tests/live-form.test.ts": 510, + "packages/web/tests/markdown.test.ts": 137, + "packages/web/tests/opener.test.ts": 508, + "packages/web/tests/page.test.ts": 32, + "packages/web/tests/responder.test.ts": 832, + "packages/web/tests/server-lifecycle.test.ts": 632, "packages/web/tests/server.test.ts": 1031, - "packages/workflow/tests/generated-observations.test.ts": 591, - "packages/workflow/tests/retained-run.test.ts": 1209, - "packages/workflow/tests/service-denial.test.ts": 67, - "packages/workflow/tests/workflow-bundle.test.ts": 724, - "packages/workflow/tests/workflow-definition.test.ts": 343, - "packages/workflow/tests/workflow-fork.test.ts": 300, - "packages/workflow/tests/workflow-run.test.ts": 1070, - "packages/workflow/tests/workspace-effect.test.ts": 1378, - "scripts/tests/adapter-vendor.test.ts": 155, - "scripts/tests/bootstrap-npm-package.test.ts": 5520, - "scripts/tests/bump-version.test.ts": 82, + "packages/workflow/tests/generated-observations.test.ts": 533, + "packages/workflow/tests/retained-run.test.ts": 1282, + "packages/workflow/tests/service-denial.test.ts": 58, + "packages/workflow/tests/workflow-bundle.test.ts": 695, + "packages/workflow/tests/workflow-definition.test.ts": 348, + "packages/workflow/tests/workflow-fork.test.ts": 301, + "packages/workflow/tests/workflow-run.test.ts": 1066, + "packages/workflow/tests/workspace-effect.test.ts": 1462, + "scripts/tests/adapter-vendor.test.ts": 157, + "scripts/tests/bootstrap-npm-package.test.ts": 5374, + "scripts/tests/bump-version.test.ts": 88, "scripts/tests/changed-paths.test.ts": 39, - "scripts/tests/ci-workflow.test.ts": 1899, - "scripts/tests/consumer-cycle.test.ts": 106, - "scripts/tests/filesystem-contract-workflow.test.ts": 81, - "scripts/tests/main-green.test.ts": 296, - "scripts/tests/main-health.test.ts": 100, - "scripts/tests/no-module-scoped-registry.test.ts": 889, - "scripts/tests/no-redundant-test-scope.test.ts": 4955, - "scripts/tests/no-sync-filesystem.test.ts": 4509, - "scripts/tests/no-yield-in-finally.test.ts": 893, - "scripts/tests/oxlint-policy.test.ts": 10632, - "scripts/tests/packaged-document.test.ts": 73, - "scripts/tests/prefer-effection-operation.test.ts": 6080, - "scripts/tests/prefer-effection-result.test.ts": 4135, - "scripts/tests/publish-workflow-membership.test.ts": 96, - "scripts/tests/review-infrastructure.test.ts": 1767, - "scripts/tests/runtime-exclusions.test.ts": 300, - "scripts/tests/runtime-tests.test.ts": 77, - "scripts/tests/scope-bound-event-registration.test.ts": 4462, - "scripts/tests/staged-write.test.ts": 65, - "scripts/tests/test-file-discovery.test.ts": 233, - "scripts/tests/test-shards.test.ts": 43, + "scripts/tests/ci-workflow.test.ts": 1886, + "scripts/tests/consumer-cycle.test.ts": 105, + "scripts/tests/filesystem-contract-workflow.test.ts": 82, + "scripts/tests/main-green.test.ts": 292, + "scripts/tests/main-health.test.ts": 107, + "scripts/tests/no-module-scoped-registry.test.ts": 856, + "scripts/tests/no-redundant-test-scope.test.ts": 4891, + "scripts/tests/no-sync-filesystem.test.ts": 4519, + "scripts/tests/no-yield-in-finally.test.ts": 884, + "scripts/tests/oxlint-policy.test.ts": 10422, + "scripts/tests/packaged-document.test.ts": 75, + "scripts/tests/prefer-effection-operation.test.ts": 5919, + "scripts/tests/prefer-effection-result.test.ts": 4091, + "scripts/tests/publish-workflow-membership.test.ts": 94, + "scripts/tests/review-infrastructure.test.ts": 1854, + "scripts/tests/runtime-exclusions.test.ts": 326, + "scripts/tests/runtime-tests.test.ts": 80, + "scripts/tests/scope-bound-event-registration.test.ts": 4515, + "scripts/tests/staged-write.test.ts": 69, + "scripts/tests/test-file-discovery.test.ts": 248, + "scripts/tests/test-shards.test.ts": 47, "scripts/tests/test-weights.test.ts": 206, - "scripts/tests/tracked.test.ts": 38, - "scripts/tests/verify-coordinator.test.ts": 222, - "scripts/tests/version-lockstep.test.ts": 116, - "scripts/tests/web-client-module.test.ts": 59, - "scripts/tests/workspace.test.ts": 45 + "scripts/tests/tracked.test.ts": 39, + "scripts/tests/verify-coordinator.test.ts": 225, + "scripts/tests/version-lockstep.test.ts": 125, + "scripts/tests/web-client-module.test.ts": 96, + "scripts/tests/workspace.test.ts": 70 } } } From ee8df6f91f3349a1f88205eb112ecde8fafb0767 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 12:46:09 -0400 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=90=9B=20Carry=20what=20a=20spawned?= =?UTF-8?q?=20child's=20bytes=20are=20across=20the=20join?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `` reduced each child to one string and wrote that string into the caller's region as ordinary text. Exact presentation is a provenance this execution records against the segment objects canonical expansion marked, and those segments never leave the child — so a program's approved source rendered inside a `` arrived in the caller as prose, was reflowed and had its markers eaten, and was published as if a person had written it. The durable close held the same one string, so a resumed run could not tell either. A child now closes with its emission runs: consecutive segments of one disposition, in order, each saying whether it is prose or source. The join writes one segment per run into the caller's region and marks the source ones there, against the segments that region actually holds. What a replay reads is the child's own record of what it produced, and a record this version cannot read is prose — the same answer an unmarked segment gets. `ALL3` now states the close's shape, because the value it asserts is the one this change is about. --- packages/core/src/expand.ts | 69 ++++++++++++++-- packages/core/tests/all.test.ts | 9 ++- .../tests/declared-markdown-component.test.ts | 79 ++++++++++++++++++- 3 files changed, 146 insertions(+), 11 deletions(-) diff --git a/packages/core/src/expand.ts b/packages/core/src/expand.ts index 91d990248..6d4935bd9 100644 --- a/packages/core/src/expand.ts +++ b/packages/core/src/expand.ts @@ -104,6 +104,7 @@ import type { } from "./execution-declarations.ts"; import { regionStream } from "./expansion-region.ts"; import { emissions } from "./render.ts"; +import type { Emission } from "./render.ts"; import { printsErrors, usePrintErrors } from "./component-failures.ts"; import { containedLedger, recoveringLedger, refuseCheckedFailure } from "./component-failures.ts"; import type { CheckedFailures } from "./component-failures.ts"; @@ -2325,7 +2326,7 @@ function spawnEnvironment(incoming: EvalEnv | undefined): EvalEnv { } /** - * Expand one `` body into the string its child closes with. + * Expand one `` body into the emission runs its child closes with. * * Everything mutable the ordinary walk threads is allocated here rather than * inherited: the binding environment and its live overlay, an eval scope the @@ -2348,7 +2349,7 @@ function spawnChild( path: string, inherited: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, -): Operation { +): Operation { return scoped(function* () { yield* provideEnv(spawnEnvironment(incoming)); yield* provideEvalScope(yield* useEvalScope()); @@ -2379,7 +2380,13 @@ function spawnChild( undefined, ); yield* refuseCheckedFailure(ledger); - return renderSegments(segments); + // Runs rather than one joined string. What a child produced is prose, or a + // program's approved source, or both in order — and exact presentation is a + // provenance this execution recorded against the segments it marked. Those + // segments do not leave the child, so the child states what they were: a + // string would arrive in the caller as prose, and a durable close holding + // one could not say otherwise on a replay either. + return emissions(environment?.sourceSegments, segments); }); } @@ -2447,13 +2454,61 @@ function* expandAll( const rendered = scope.get(DurableContext) === undefined ? yield* all(children.map((child) => child())) - : yield* durableAll(children.map((child) => (): Workflow => ephemeral(child()))); + : (yield* durableAll( + children.map((child) => (): Workflow => ephemeral(retained(child()))), + )).map(readEmissions); - for (const text of rendered) { - if (text !== "") { - owner.push({ type: "text", content: text }); + for (const runs of rendered) { + for (const run of runs) { + if (run.text === "") { + continue; + } + // One segment per run, and the exact ones are marked again here: the + // record is keyed by segment identity, and these segments are this + // region's, not the child's. A child that ran on a previous attempt says + // what its runs were through its own durable close, so a replay marks + // exactly what the live run marked. + const segment: Segment = { type: "text", content: run.text }; + owner.push(segment); + if (run.exact) { + markExactSource(environment?.sourceSegments, [segment]); + } + } + } +} + +/** One child's runs, as its durable close retains them. */ +function retained(child: Operation): Operation { + return (function* (): Operation { + return (yield* child).map((run) => ({ text: run.text, exact: run.exact })); + })(); +} + +/** + * The runs a child closed with, read back from what the journal holds. + * + * Parsed rather than trusted: a replay hands back whatever the history has, and + * a record that is not a list of runs is a record this version cannot read. A + * run it cannot read is not presented as source — the safe answer, and the same + * one an unmarked segment gets. + */ +function readEmissions(value: Json): Emission[] { + if (!Array.isArray(value)) { + return []; + } + const runs: Emission[] = []; + for (const entry of value) { + if (entry === null || typeof entry !== "object" || Array.isArray(entry)) { + continue; + } + const text = (entry as { [key: string]: Json })["text"]; + const exact = (entry as { [key: string]: Json })["exact"]; + if (typeof text !== "string" || typeof exact !== "boolean") { + continue; } + runs.push({ text, exact }); } + return runs; } function printErrorsPropError(segment: ComponentElement, message: string): ErrorSegment { diff --git a/packages/core/tests/all.test.ts b/packages/core/tests/all.test.ts index e2becf15a..63ae88daf 100644 --- a/packages/core/tests/all.test.ts +++ b/packages/core/tests/all.test.ts @@ -472,11 +472,14 @@ describe("Tier ALL — PA2: durable identity follows the source", () => { { id: "root.0", status: "ok" }, { id: "root", status: "ok" }, ]); - // Each child closes with exactly the markdown it rendered. + // Each child closes with exactly the markdown it rendered, and with what + // that markdown is: a run says whether those bytes are prose or a program's + // approved source, because the segments they came from do not leave the + // child and a replay has nothing else to read the disposition from. expect(new Map(childCloseValues(result.events))).toEqual( new Map([ - ["root.1", "[two]"], - ["root.0", "[one]"], + ["root.1", [{ text: "[two]", exact: false }]], + ["root.0", [{ text: "[one]", exact: false }]], ]), ); }); diff --git a/packages/core/tests/declared-markdown-component.test.ts b/packages/core/tests/declared-markdown-component.test.ts index 17fbadd2c..dd1beece8 100644 --- a/packages/core/tests/declared-markdown-component.test.ts +++ b/packages/core/tests/declared-markdown-component.test.ts @@ -1389,6 +1389,7 @@ function* published( source: string, declarations: readonly MarkdownComponent[], extra: readonly ExecutionInstallation[], + stream: InMemoryStream = new InMemoryStream(), ): Operation { const chunks: string[] = []; return yield* scoped(function* () { @@ -1404,7 +1405,7 @@ function* published( yield* executeInstalled( { ...retainedSource(ROOT_PATH, source), - stream: new InMemoryStream(), + stream, includes: [], }, [installation(declarations), ...extra], @@ -1560,6 +1561,82 @@ describe("Tier DM — exact source is a provenance, not a field", () => { expect(unpresented(output)).toBe(false); expect(output).not.toContain("**these**"); }); + + it("DM54: a spawned child's exact source is still source", function* () { + // `` joins its children by value, so what crosses the join says what + // it is. A child that reduced its region to one string would hand the + // caller prose, and the approved bytes a `` rendered would be + // presented — reflowed, its markers eaten — as if a person had written them. + const inside = yield* published( + [ + "", + "", + "", + "", + "", + "ordinary prose", + "", + "", + "", + ].join("\n"), + [declared(PRESENTABLE, { exact: true })], + [], + ); + + expect(unpresented(inside)).toBe(true); + // And the sibling that rendered prose is still prose: the join does not + // make one child's disposition the other's. + expect(inside).toContain("ordinary prose"); + }); + + it("DM54: a replayed child restores what its bytes were", function* () { + // The disposition is a fact about what canonical expansion produced, and + // the segments it marked do not survive the process. A replay therefore + // reads it from the child's own durable close — and a close that retained + // only text could not answer at all. + const source = [ + "", + "", + "", + "", + "", + "ordinary prose", + "", + "", + "", + ].join("\n"); + const declarations = [declared(PRESENTABLE, { exact: true })]; + const stream = new InMemoryStream(); + const live = yield* published(source, declarations, [], stream); + expect(unpresented(live)).toBe(true); + + // The children's own closes, without the root's: the parent runs again and + // restores each child from what it recorded, which is the state a resumed + // run is actually in. + const history = (yield* stream.readAll()).filter( + (event) => !(event.type === "close" && event.coroutineId === "root"), + ); + const children = history.filter( + (event) => event.type === "close" && event.coroutineId.includes("."), + ); + expect(children).toHaveLength(2); + // What each child retained says what its bytes were, not only what they said. + // What each child retained says what its bytes were, not only what they + // said. Read as a set: children close in whatever order they finished, and + // which one finished first is exactly what this must not depend on. + const runs = children.flatMap((event) => + event.type === "close" && event.result.status === "ok" && Array.isArray(event.result.value) + ? (event.result.value as { text: string; exact: boolean }[]) + : [], + ); + expect(runs.filter((run) => run.exact)).toEqual([{ text: PRESENTABLE, exact: true }]); + expect(runs.some((run) => !run.exact && run.text.includes("ordinary prose"))).toBe(true); + + const replayed = yield* published(source, declarations, [], new InMemoryStream(history)); + + expect(replayed).toBe(live); + expect(unpresented(replayed)).toBe(true); + }); }); /** From a7e59558c436117f94ed8f30ef3205c029881615 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 13:07:21 -0400 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=90=9B=20Refuse=20a=20spawned=20chi?= =?UTF-8?q?ld's=20close=20this=20version=20cannot=20read?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading the runs a child retained failed open: a value that was not a list read as no runs, and a member that would not read was skipped. A history damaged in either way replayed *successfully* and published a document with exactly the part it could not read missing — which looks like a child that rendered nothing rather than a history nobody can rebuild. It is parsed whole now, and refused whole: not a list, a member that is not a run, a run missing one of its two members or carrying a third, each fails the run. Nothing is reconstructed partially, and nothing is cast on the way in. The two contracts say what the close holds, because they still described the string it used to be: a child closes with the ordered `{ text, exact }` runs it rendered, that is where the exact-source provenance crosses a join the segments themselves do not, and a close that will not read fails the run. The conformance matrix names the four cases that hold this, each under its own identifier. --- architecture.md | 6 +- packages/core/src/expand.ts | 38 ++++++++---- .../tests/declared-markdown-component.test.ts | 61 ++++++++++++++++++- specs/executable-mdx-spec.md | 15 ++++- 4 files changed, 103 insertions(+), 17 deletions(-) diff --git a/architecture.md b/architecture.md index 0e4fbb719..27bce7b55 100644 --- a/architecture.md +++ b/architecture.md @@ -3318,7 +3318,11 @@ coroutine of the one that reached the ``, and nesting produces the existing hierarchical identity. Effects inside a child keep their ordinary descriptions under that coroutine, so two children may derive the same local block id without colliding, and work after `` continues on the parent counter it would have -had without any child. Each successful child closes with its rendered string. +had without any child. Each successful child closes with the ordered `{ text, exact }` runs it +rendered. Exact presentation is a provenance recorded against the segment +objects expansion marked, and those segments do not cross the join — so the runs +are what carries it, live and on replay alike, and a retained close that does +not read as that shape fails the run instead of rebuilding part of a document. **Output is authored order; the journal is completion order.** A child emits into its private buffer, and `` appends the renderings to its caller's diff --git a/packages/core/src/expand.ts b/packages/core/src/expand.ts index 6d4935bd9..114a640fd 100644 --- a/packages/core/src/expand.ts +++ b/packages/core/src/expand.ts @@ -132,10 +132,15 @@ import { createReturnBody, missingReturnMessage } from "./return-flow.ts"; import type { ReturnBody } from "./return-flow.ts"; import { unbox, useEvalScope } from "@effectionx/scope-eval"; import type { EvalScope } from "@effectionx/scope-eval"; -import { DurableContext, durableAll, ephemeral } from "@executablemd/durable-streams"; +import { + DurableContext, + durableAll, + ephemeral, + StaleInputError, +} from "@executablemd/durable-streams"; import type { Workflow } from "@executablemd/durable-streams"; import { SchemaValidationError, validateProps, validateReturnValue } from "./validate.ts"; -import { parseJson } from "./json.ts"; +import { isJsonObject, parseJson } from "./json.ts"; import { healSegment } from "./heal.ts"; import { scanSegments } from "./scanner.ts"; import { declareChildAnswers, expandAnswers, strayAnswerError } from "./answers.ts"; @@ -2484,27 +2489,34 @@ function retained(child: Operation): Operation { })(); } +/** What a child's retained close is refused with when it will not read. */ +const UNREADABLE_RUNS = + "a spawned child's retained close cannot be read as what it rendered, so this run cannot " + + "rebuild the document that child produced. A history is read whole or not at all."; + /** * The runs a child closed with, read back from what the journal holds. * - * Parsed rather than trusted: a replay hands back whatever the history has, and - * a record that is not a list of runs is a record this version cannot read. A - * run it cannot read is not presented as source — the safe answer, and the same - * one an unmarked segment gets. + * Parsed whole, and refused whole. A replay hands back whatever the history has; + * skipping a member it cannot read, or reading a value that is not a list of + * runs as an empty one, would publish a document missing exactly the part that + * could not be read — and it would look like a document that rendered nothing + * there. So every member is checked, the shape is closed at the two members a + * run has, and anything else fails this run rather than shortening its output. */ function readEmissions(value: Json): Emission[] { if (!Array.isArray(value)) { - return []; + throw new StaleInputError(UNREADABLE_RUNS); } const runs: Emission[] = []; for (const entry of value) { - if (entry === null || typeof entry !== "object" || Array.isArray(entry)) { - continue; + if (!isJsonObject(entry)) { + throw new StaleInputError(UNREADABLE_RUNS); } - const text = (entry as { [key: string]: Json })["text"]; - const exact = (entry as { [key: string]: Json })["exact"]; - if (typeof text !== "string" || typeof exact !== "boolean") { - continue; + const text = entry["text"]; + const exact = entry["exact"]; + if (Object.keys(entry).length !== 2 || typeof text !== "string" || typeof exact !== "boolean") { + throw new StaleInputError(UNREADABLE_RUNS); } runs.push({ text, exact }); } diff --git a/packages/core/tests/declared-markdown-component.test.ts b/packages/core/tests/declared-markdown-component.test.ts index dd1beece8..282e3edf5 100644 --- a/packages/core/tests/declared-markdown-component.test.ts +++ b/packages/core/tests/declared-markdown-component.test.ts @@ -1434,6 +1434,20 @@ function answeringOpenName(definition: ImportedDefinition): ExecutionInstallatio }; } +/** One replay that is expected to refuse, with whatever it managed to publish. */ +function* refusalOfRun( + source: string, + declarations: readonly MarkdownComponent[], + history: readonly DurableEvent[], +): Operation<{ failed: boolean; output: string }> { + try { + const output = yield* published(source, declarations, [], new InMemoryStream([...history])); + return { failed: false, output }; + } catch { + return { failed: true, output: "" }; + } +} + describe("Tier DM — exact source is a provenance, not a field", () => { it("DM49: a declared component the host called exact emits its bytes unpresented", function* () { // The positive control. Without it the two refusals below would pass for a @@ -1589,7 +1603,7 @@ describe("Tier DM — exact source is a provenance, not a field", () => { expect(inside).toContain("ordinary prose"); }); - it("DM54: a replayed child restores what its bytes were", function* () { + it("DM55: a replayed child restores what its bytes were", function* () { // The disposition is a fact about what canonical expansion produced, and // the segments it marked do not survive the process. A replay therefore // reads it from the child's own durable close — and a close that retained @@ -1637,6 +1651,51 @@ describe("Tier DM — exact source is a provenance, not a field", () => { expect(replayed).toBe(live); expect(unpresented(replayed)).toBe(true); }); + + it("DM56: a child's close this version cannot read fails the run, and publishes nothing", function* () { + const source = [ + "", + "", + "", + "", + "", + "ordinary prose", + "", + "", + "", + ].join("\n"); + const declarations = [declared(PRESENTABLE, { exact: true })]; + const stream = new InMemoryStream(); + yield* published(source, declarations, [], stream); + const complete = (yield* stream.readAll()).filter( + (event) => !(event.type === "close" && event.coroutineId === "root"), + ); + + // Every way a retained close can stop being a list of runs: a value that is + // not a list, a member that is not a run, a member missing one of the two + // things a run is, and a member carrying something else besides. + const damaged: Json[] = [ + "not emission runs", + [{ text: PRESENTABLE }], + [{ text: PRESENTABLE, exact: "yes" }], + [{ text: PRESENTABLE, exact: true, presented: false }], + [PRESENTABLE], + ]; + + for (const value of damaged) { + const history = complete.map((event) => + event.type === "close" && event.coroutineId.endsWith(".0") + ? { ...event, result: { status: "ok" as const, value } } + : event, + ); + const published_ = yield* refusalOfRun(source, declarations, history); + + // Refused, and nothing published: a document rebuilt without the part it + // could not read is a document that never existed. + expect([JSON.stringify(value), published_.failed]).toEqual([JSON.stringify(value), true]); + expect([JSON.stringify(value), published_.output]).toEqual([JSON.stringify(value), ""]); + } + }); }); /** diff --git a/specs/executable-mdx-spec.md b/specs/executable-mdx-spec.md index 6d5456e0c..87e4cb61f 100644 --- a/specs/executable-mdx-spec.md +++ b/specs/executable-mdx-spec.md @@ -6810,10 +6810,17 @@ protocol's §7). Each child also gets a fresh block counter and an expansion pat extended by its authored ordinal, so two children may derive the same local block id without colliding — the child coroutine namespaces it — and the work after `` continues on the parent counter it would have had anyway. Each -successful child closes with its rendered string. A complete replay runs no +successful child closes with the ordered runs it rendered: consecutive segments +of one disposition, each `{ text, exact }`, where `exact` says whether those +bytes are a program's approved source rather than prose (§5.3). The segments a +child marked never leave it, so the run is where that provenance crosses the +join — a close holding only text could not say what its bytes were, and a +replayed child's source would be published as prose. A complete replay runs no spawned work and rebuilds the output from those closes; a partial replay restores the children that closed and resumes only the unrecorded ones, under -the same identities. Inserting, removing or reordering spawns is a definition +the same identities. A retained close that does not read as that exact shape — +not a list, a member that is not a run, a run missing or exceeding its two +members — fails the run rather than contributing part of a document. Inserting, removing or reordering spawns is a definition change and follows the ordinary divergence contract. **Failure and cancellation.** The join is fail-fast. The first child failure @@ -13309,6 +13316,10 @@ what they observe is what a person's terminal would show. | DM50 | An ordinary declaration is prose | The same bytes from a declaration the host did not call exact are stripped, collapsed and formatted | | DM51 | A middleware answer cannot claim it | `Component.importComponent` middleware answering an open name with a definition carrying the disposition gets prose; nothing admitted that definition, so nothing about it is exact | | DM52 | A mark this engine did not make is nothing | A segment carrying the disposition as a field is not exact, whoever supplied it; expansion also rebuilds text segments, so such a field never reaches emission in the first place | +| DM53 | The record is not reachable by name | A component that builds a context with the record's name and writes to it publishes prose | +| DM54 | A spawned child's source is still source | A declared exact component rendered inside ``/`` keeps its bytes unpresented, and a prose sibling stays prose | +| DM55 | A replayed child restores what its bytes were | Each child's retained close holds its ordered `{ text, exact }` runs, and replaying that history reproduces the live output with the same provenance | +| DM56 | A close that will not read fails the run | A retained child close that is not a list of runs, or holds a member that is not one, refuses atomically and publishes nothing | ### Tier MDK — Declaring exact Markdown with `Markdown({…})` (§5.3) From 54db7cfe93260231fbb467add2ecb4dbc7de1226 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 14:16:37 -0400 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=90=9B=20Correlate=20a=20canonical?= =?UTF-8?q?=20import=20at=20its=20own=20terminal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two `` children may have imports in flight at once, so the frame a canonical selection belongs to could be neither the last one anybody opened nor the one opened where the code happens to be running. Keying frames by the exact Effection scope isolated siblings but lost the import as soon as ordinary middleware delegated `next` from a scope of its own, which is legitimate and which a document cannot see. The association is now the import's own terminal. One authored import creates one frame — a closure in no map, under no key — and one `Component` descriptor whose core `importComponent` handler closes over it. The descriptor carries the stable `Component` name, so it receives every installed handler in the same order as the public one: a stable name shares middleware, and shares no terminal authority. `next` terminates in the terminal that dispatch was created with, however many descendant scopes a handler delegates through, and sibling spawns ask through different descriptors. The execution's ordinary provider delegates first and falls back to canonical resolution only when nothing answered, so a direct `importComponent()` a handler starts for itself is a separate import that names no frame. What says "nothing answered" is a namespaced, non-enumerable mark on what an empty public terminal raises, carrying the name it was asked for — not the error's class. The readers are in a different copy of core than the writer as often as not: a component loaded with `--include`, and a middleware package holding its own copy, each build their own descriptor with their own terminal and their own class, and an `instanceof` check turned a nested import of theirs into a "no provider" failure that took the authored import down with it. The whole mark is parsed rather than trusted, and a mark naming another component is somebody else's failure. Component-answer windows keep the explicit, serial window object #857 settled on: they are captured before a provider's handler runs, so a handler delegating through a descendant scope answers the resolution it was opened in, and no scope takes part. The scope arguments and the rendezvous machinery the concurrent reading needed are gone from those rows, and the per-installation answer set says why it is a set without claiming two windows are ever open at once. The evidence holds two imports open *together* by suspending inside the import itself, which is the only arrangement in which one could take a sibling's selection: two live imports each select into their own frame in either release order, and cancelling one while the other is live closes only its own frame — the survivor names exactly what that site names when nothing is torn down beside it. A handler delegating through `scoped()` keeps its identity; nested imports shadow and restore without a stack; a foreign copy's nested import resolves ordinarily while the authored element keeps the only identity; delegating twice, delegating another name, or reporting about an import nobody asked for still names nothing. DM56 now reads the chunks the failing run actually published and asserts the `StaleInputError` it caught, so both halves of that row are evidence. Both contracts say what the correlation is, because they still described the scope: the import's private terminal closure, a stable Api name that shares middleware rather than terminal authority, and a handler's own nested import as a separate import rather than a delegation of the authored one. --- architecture.md | 67 +- packages/core/src/component-answers.ts | 12 +- packages/core/src/component-api.ts | 124 +- .../src/components/component-resolution.ts | 102 +- packages/core/src/execute.ts | 119 +- packages/core/src/execution-environment.ts | 21 + packages/core/src/expand.ts | 25 +- packages/core/src/invocation-identity.ts | 149 +-- packages/core/tests/all.test.ts | 162 ++- packages/core/tests/answer-identity.test.ts | 1159 +++++------------ .../tests/declared-markdown-component.test.ts | 40 +- .../core/tests/invocation-identity.test.ts | 431 +++++- specs/executable-mdx-spec.md | 48 +- 13 files changed, 1338 insertions(+), 1121 deletions(-) diff --git a/architecture.md b/architecture.md index 27bce7b55..2d8678bbd 100644 --- a/architecture.md +++ b/architecture.md @@ -3993,7 +3993,8 @@ matching name says nothing about which registration answered. What settles it is the selection itself, recorded where it is made: - expansion opens an **execution-private import frame** before it asks the - public import chain anything, in the Effection scope that is asking; + public import chain anything, and hands it to the terminal it builds for that + one import; - canonical core resolution records, inside that frame, the exact name it was asked for and the exact implementation it selected — the function object this execution built from the host's factory, by identity; @@ -4014,30 +4015,52 @@ answered; and a replay decides the same way, against this execution's own factory-created implementation rather than against anything a previous run recorded. -**Frames are owned per Effection scope, not per execution.** `` gives two -`` children imports in flight at the same time, so "the frame this -selection belongs to" can no longer mean "the last one anybody opened". Each -scope keeps its own LIFO stack of open frames, and a canonical selection is -recorded into the top frame of the scope that is resolving: - -- nesting inside one scope is unchanged — an inner import owns the top until it - closes, and the outer one may be selected into again afterwards; -- sibling spawns have independent tops, so one spawned child's selection can - never land in another's frame, and closing or cancelling one spawn neither - clears nor authorizes the other; -- a frame is removed only by the settle that opened it, from the scope that - opened it, and teardown discards every remaining stack; and +**A frame is owned by the import's own terminal, not by an Effection scope and +not by the execution.** `` gives two `` children imports in flight at +the same time, so "the frame this selection belongs to" can be neither "the last +one anybody opened" nor "the one opened where this code happens to be running". +Each import creates its own frame and its own `Component` Api descriptor whose +core `importComponent` handler closes over that frame; the engine asks through +that descriptor, and the selection is recorded by the terminal `next` reaches: + +- the descriptor carries the same stable Api name as the public one, so it + receives the same installed middleware in the same order — **a stable name + shares middleware, and shares no terminal authority**; +- middleware may observe, delegate, replace or refuse the answer, and may run + `next` in any descendant scope: `next` still terminates in the terminal that + dispatch was created with, so delegating through a scope of its own keeps the + identity; +- sibling spawns resolve through different descriptors, so one spawned child's + selection cannot land in another's frame, and closing or cancelling one + neither clears nor authorizes the other; +- nesting is unchanged and needs no stack: an inner authored import is its own + dispatch with its own terminal, so the outer one is neither shadowed nor + inferred from scheduling; +- a handler that starts an import of its own by calling the public operation is + making a **separate** import, not delegating the authored one — it may resolve + normally, and it grants the authored import no identity; and - two selections in *one* frame — a handler delegating twice — still yield no domain, which remains the safe direction. -The scope object is a private key. It is never published, never read from, and -never reaches a document, a component, a provider or a handler: two frames -belong together because they were opened under the same engine scope, not -because of anything either of them says. The same ownership governs the -canonical answer windows a provider claims through, where one installation may -hold an answer open in two sibling spawns at once — the exact same definition -included, because a reusable provider owns one object and a claim is per -window — and a second, *different* answer in either still refuses. +The frame is a closure and nothing else: it is in no map, under no key, and +reachable only from the dispatch that opened it. Nothing is published, keyed or +read from — not a scope, not a context, not a token, and not a durable coroutine +id, which non-journaled expansion does not have. A counterfeit descriptor made +with the same Api name changes only what is asked through that counterfeit; it +cannot become the terminal of the engine's own call. Live expansion and replay +decide this the same way. + +Canonical answer windows are owned the same way and by the same kind of value — +an explicit object rather than a scope — but serially: component answers are +resolved in one capture phase before any document expands, so one window is open +at a time. Each provider request captures that window object before its handler +runs, a claim states it back explicitly, and a handler delegating through a +descendant scope answers the resolution it was opened in. One installation may +answer more than one import with the same definition — a reusable provider owns +one object and a claim is per window — and a second, *different* answer in +either still refuses. Concurrent document imports happen after capture, with no +window open at all: such an import may be answered as ordinary middleware, and +acquires no profile identity. The engine then mints one issuance per invocation, carrying that domain — or none — the authored name for what a refusal says, and the frame the body is diff --git a/packages/core/src/component-answers.ts b/packages/core/src/component-answers.ts index fa283dc2c..05ba2a835 100644 --- a/packages/core/src/component-answers.ts +++ b/packages/core/src/component-answers.ts @@ -39,7 +39,6 @@ * do is enter an admitted fragment. */ -import { useScope } from "effection"; import type { Operation } from "effection"; import { Component } from "./component-api.ts"; @@ -115,11 +114,12 @@ export function componentAnswerRegistrar( *around(handler: ComponentAnswerHandler): Operation { yield* Component.around({ *importComponent([name, position], next) { - // The scope this invocation is running in, which is the spawn whose - // resolution this request answers. Read here rather than carried on - // the installation: one installation serves every spawn, and two of - // them may be resolving at the same time. - const asked = installation.open(yield* useScope(), name, position); + // One request for this handler invocation, capturing the resolution + // window that is open right now. Minted here rather than carried on + // the installation: one installation serves every name it registered, + // and a retained handle states nothing about which resolution is + // being decided. + const asked = installation.open(name, position); try { return yield* handler( asked.request, diff --git a/packages/core/src/component-api.ts b/packages/core/src/component-api.ts index 9ce938c3e..aeebd1088 100644 --- a/packages/core/src/component-api.ts +++ b/packages/core/src/component-api.ts @@ -175,16 +175,87 @@ export interface ComponentApi { registry: ComponentRegistry; } -export const Component: Api = createApi("Component", { +/** + * The mark an empty public terminal puts on what it raises: a namespaced, + * non-enumerable own property carrying the name that was asked for. + * + * A property rather than a class, because the readers are in a different copy of + * this module than the writer as often as not. A component loaded from disk with + * `--include`, and a middleware package holding its own copy of core, each build + * their own `Component` descriptor with their own empty terminal and their own + * error class — and an execution has to recognize "nothing answered this" across + * exactly that seam, which `instanceof` cannot do. The name is namespaced so it + * collides with nothing, and non-enumerable so it does not travel into whatever + * a reporter serializes. + * + * It conveys one fact — *this call reached an empty public terminal, asking for + * this name* — and no authority. Anything may put it on anything; all it can + * cause is the ordinary resolution an unanswered import gets anyway. + */ +const MISSING_IMPORT_PROVIDER = "@executablemd/core/missing-import-provider"; + +/** + * What the public descriptor's own terminal raises when nothing answered. + * + * An execution's provider delegates to `next` first and performs its ordinary + * resolution only for this, so a descriptor that supplied a terminal of its own + * is answered by that terminal and never resolved twice. Exported for core, + * published from no package entry point, and carrying nothing but the name that + * was asked. + */ +export class MissingImportProvider extends Error { + override name = "MissingImportProvider"; + constructor(asked: string) { + super( + `Component.importComponent("${asked}") has no provider. Install one with ` + + `Component.around({ importComponent }, { at: "min" }) before expansion.`, + ); + Object.defineProperty(this, MISSING_IMPORT_PROVIDER, { + value: { asked }, + enumerable: false, + writable: false, + configurable: false, + }); + } +} + +/** + * Whether `error` is an empty public terminal reporting that nothing answered an + * import of exactly `asked`. + * + * The whole mark is parsed rather than trusted: an own, non-enumerable property + * under the namespaced name, holding an object with exactly one member, `asked`, + * whose value is the name this call asked for. Nothing is cast, and a mark that + * names another component — a foreign terminal's report about a *different* + * import, arriving here on some other failure — is not this call's. + */ +export function isMissingImportProvider(error: unknown, asked: string): boolean { + if (typeof error !== "object" || error === null) { + return false; + } + const mark = Object.getOwnPropertyDescriptor(error, MISSING_IMPORT_PROVIDER); + if (mark === undefined || mark.enumerable) { + return false; + } + const value: unknown = mark.value; + if (typeof value !== "object" || value === null || Object.keys(value).length !== 1) { + return false; + } + return Object.getOwnPropertyDescriptor(value, "asked")?.value === asked; +} + +/** + * Every default but the registry, which each descriptor is given its own of: + * a `Map` living at module scope would be one table shared by every run in the + * process, and the lint rule that says so is right. + */ +const COMPONENT_DEFAULTS: Omit = { // deno-lint-ignore require-yield *importComponent( name: string, _position?: Readonly, ): Operation { - throw new Error( - `Component.importComponent("${name}") has no provider. Install one with ` + - `Component.around({ importComponent }, { at: "min" }) before expansion.`, - ); + throw new MissingImportProvider(name); }, // deno-lint-ignore require-yield *applyModifiers(_modifiers: Modifier[], block: CodeBlockContext): Operation { @@ -259,9 +330,52 @@ export const Component: Api = createApi("Component", *handleFailure(failure: ComponentFailure): Operation { throw failure.error; }, +}; + +export const Component: Api = createApi("Component", { + ...COMPONENT_DEFAULTS, registry: new Map(), }); +/** + * Ask one import through a descriptor whose terminal belongs to that import. + * + * The name is what shares middleware: a descriptor created with the stable + * `Component` name receives every handler installed anywhere, in the order they + * were installed, exactly as the public descriptor does. What a name does not + * share is the default handler — each `createApi()` instance owns its own — so + * the chain composed here terminates in the continuation this caller passed and + * in nothing a handler can reach, replace or reorder. + * + * That is the whole of the correlation. A middleware may delegate `next` through + * any descendant Effection scope and still arrive here; two imports asking at + * the same time have two descriptors and two terminals; and a counterfeit + * descriptor built with the same name changes only the calls made through it. + */ +export function importThroughTerminal( + name: string, + position: Readonly | undefined, + terminal: ( + asked: string, + at: Readonly | undefined, + ) => Operation, +): Operation { + const owned = createApi("Component", { + ...COMPONENT_DEFAULTS, + // Its own, and empty: what a registration installed is middleware, which + // this descriptor shares by name, so a registry asked through it is answered + // there exactly as it is through the public one. + registry: new Map(), + *importComponent( + asked: string, + at?: Readonly, + ): Operation { + return yield* terminal(asked, at); + }, + }); + return owned.operations.importComponent(name, position); +} + export const importComponent: Operations["importComponent"] = Component.operations.importComponent; export const applyModifiers: Operations["applyModifiers"] = diff --git a/packages/core/src/components/component-resolution.ts b/packages/core/src/components/component-resolution.ts index a87d65fc0..39393220a 100644 --- a/packages/core/src/components/component-resolution.ts +++ b/packages/core/src/components/component-resolution.ts @@ -18,8 +18,6 @@ * nothing a handler still holds decides what is *invoked*. */ -import type { Scope } from "effection"; - import type { ComponentDefinition, FunctionComponentDefinition, SourcePosition } from "../types.ts"; /** A definition an import may answer with. */ @@ -332,14 +330,14 @@ export interface OpenAnswerRequest { */ export interface ProviderInstallation { /** - * Begin one handler invocation's request for one asked name, under the engine - * scope that is resolving it. + * Begin one handler invocation's request for one asked name. * - * The scope is how the request finds the resolution it was asked in when - * several are open at once. It is a private key the caller reads from its own - * operation; nothing about it reaches the provider. + * The request captures the resolution that is open when it is minted, by + * identity, which is how it finds the asking it answers. Nothing about where + * the handler runs takes part in that, and nothing about it reaches the + * provider. */ - open(scope: Scope, name: string, position?: Readonly): OpenAnswerRequest; + open(name: string, position?: Readonly): OpenAnswerRequest; } /** An identity a provider stated in a shape this execution cannot record. */ @@ -373,7 +371,7 @@ export class CanonicalImports { */ #active = false; /** - * The resolutions each Effection scope has open, innermost last. + * The one resolution this owner has open, if it has one. * * A provider installation outlives every resolution it takes part in, while a * fresh request belongs to one handler invocation. Canonical execution asks @@ -387,14 +385,14 @@ export class CanonicalImports { * handler settled for one name from recording under it while a different * name is being resolved. * - * A stack per scope rather than one for the execution, because sibling spawns - * resolve at the same time. Nesting inside one scope stays LIFO — an inner - * resolution hides its parent until it closes — while each spawn has its own - * top, so closing or cancelling one can neither clear nor authorize the - * other. The scope object is a private key: never published, - * never read from, and never handed to a provider. + * One window at a time, because component answers are resolved in one serial + * capture phase before any document expands: the execution asks for each + * admitted name in turn, and nothing concurrent is resolving beside it. A + * request captures the window object itself before its handler runs, so a + * handler delegating through any number of descendant scopes still answers the + * resolution it was opened in — no scope takes part in this at all. */ - readonly #windows = new Map(); + #window: ResolutionWindow | undefined; /** How many resolutions this owner has opened, so each one is its own. */ #occurrences = 0; /** @@ -406,10 +404,10 @@ export class CanonicalImports { * what it resolved to. * * A set of windows per installation rather than the last one it answered. - * Two windows can be open at once now, so one installation may legitimately - * answer in window A and then in window B — and a second, different answer - * in A must still refuse, even though B was answered in between. Remembering - * only the most recent window would have let that second answer through. + * Windows follow one another, and one installation may legitimately answer in + * window A and then in window B — while a request kept from A may still try to + * state a second, different answer for A after B was answered. Remembering only + * the most recent window would have let that one through. * * Keyed by the installation's own frozen token, so an installation stays * reusable: it answers several admitted names and the same name resolved more @@ -425,9 +423,9 @@ export class CanonicalImports { /** Stop. Called at teardown, on completion, failure or cancellation. */ revoke(): void { this.#active = false; - // Every scope's stack, not only the ones that emptied themselves: a spawn - // torn down with a resolution still open leaves nothing claimable. - this.#windows.clear(); + // Whatever was open goes with it: an execution torn down mid-resolution + // leaves nothing claimable. + this.#window = undefined; } get identifying(): boolean { @@ -443,7 +441,7 @@ export class CanonicalImports { * one: there is no path from a document, a component or a provider to this * method. */ - beginResolution(name: string, scope: Scope): ResolutionWindow { + beginResolution(name: string): ResolutionWindow { if (!this.#active) { throw new AnswerIdentityError(REVOKED_ANSWER_IDENTIFICATION); } @@ -454,31 +452,14 @@ export class CanonicalImports { name, occurrence, close(): void { - // Only this window, and only out of the scope that opened it. A nested - // resolution above it has its own close, and a sibling spawn's stack - // is not touched at all — clearing either would settle a decision still - // being made somewhere else. Removed by identity, so no bookkeeping - // value has to be trusted to say which window this is, and idempotent, - // because a close that ran twice would otherwise remove its parent. - const open = owner.#windows.get(scope); - if (open === undefined) { - return; - } - const index = open.lastIndexOf(window); - if (index >= 0) { - open.splice(index, 1); - } - if (open.length === 0) { - owner.#windows.delete(scope); + // By identity, and idempotent: a close that ran twice must not clear a + // window somebody else opened afterwards. + if (owner.#window === window) { + owner.#window = undefined; } }, }; - const open = this.#windows.get(scope); - if (open === undefined) { - this.#windows.set(scope, [window]); - } else { - open.push(window); - } + this.#window = window; return window; } @@ -500,13 +481,13 @@ export class CanonicalImports { const installation = Object.freeze({}); const owner = this; return { - open(scope: Scope, name: string, position?: Readonly): OpenAnswerRequest { - // Captured by identity, here, at the moment this invocation begins, out - // of the scope that is resolving. A request minted while resolution N - // is open answers resolution N or nothing: it holds the object, so it - // cannot be made to describe whichever window is open later — or a - // window a sibling spawn opened in the meantime. - const opened = owner.#windows.get(scope)?.at(-1); + open(name: string, position?: Readonly): OpenAnswerRequest { + // Captured by identity, here, at the moment this invocation begins. A + // request minted while resolution N is open answers resolution N or + // nothing: it holds the object, so it cannot be made to describe + // whichever window is open later, and running its handler in a + // descendant scope changes nothing about which window it captured. + const opened = owner.#window; let live = true; const request: ComponentAnswerRequest = Object.freeze({ name, @@ -519,7 +500,7 @@ export class CanonicalImports { return owner.#record( installation, origin, - { name, window: opened, scope, live: () => live }, + { name, window: opened, live: () => live }, answer, stated, ); @@ -541,7 +522,6 @@ export class CanonicalImports { asked: { name: string; window: ResolutionWindow | undefined; - scope: Scope; live: () => boolean; }, answer: ImportedDefinition, @@ -552,15 +532,11 @@ export class CanonicalImports { } // Four questions, and each of them is about the invocation rather than // about the provider: is this handler still deciding; is the resolution it - // was asked in the one still open, by identity; and is the name it was - // asked the name that resolution is deciding. A stable installation handle - // answers none of them, which is why it does not claim. - // Four questions, and the window one is asked of the scope that resolved: - // being the innermost open resolution somewhere else in the execution is - // not being the one this handler was asked in. + // was asked in the one still open, by identity; and is the name it was asked + // the name that resolution is deciding. A stable installation handle answers + // none of them, which is why it does not claim. const open = asked.window; - const top = this.#windows.get(asked.scope)?.at(-1); - if (!asked.live() || open === undefined || open !== top || open.name !== asked.name) { + if (!asked.live() || open === undefined || open !== this.#window || open.name !== asked.name) { throw new AnswerIdentityError(SETTLED_CLAIM); } const identity = complete(origin, stated); diff --git a/packages/core/src/execute.ts b/packages/core/src/execute.ts index a0b3bc8aa..249aada59 100644 --- a/packages/core/src/execute.ts +++ b/packages/core/src/execute.ts @@ -93,7 +93,7 @@ import { filesFatalFailure, useSegmentCauses, } from "./errors.ts"; -import { Component, importComponent, raise } from "./component-api.ts"; +import { Component, importComponent, isMissingImportProvider, raise } from "./component-api.ts"; import { sourceDescription } from "./source-position.ts"; import { emissions, exactly, renderSegment } from "./render.ts"; import { createExactSource } from "./output/exact-source.ts"; @@ -142,7 +142,7 @@ import { installIdentities, parseFormDeclaration, } from "./invocation-identity.ts"; -import type { IdentityComponent } from "./invocation-identity.ts"; +import type { IdentityComponent, ImportSelection } from "./invocation-identity.ts"; import { CanonicalImports, ExecutionImports, @@ -846,7 +846,7 @@ function* resolveComponentAnswers( ) { return answer; } - const asked = canonicalProvider.open(yield* useScope(), name, position); + const asked = canonicalProvider.open(name, position); try { return asked.request.claim(answer, { key: name, revision: CORE_REVISION }); } finally { @@ -866,7 +866,7 @@ function* resolveComponentAnswers( // One call, one result. The claim and core's copy of what was claimed // come back together, and the object the chain returned is not read // again — so nothing this run keeps was decided by a second read. - const resolution = imports.beginResolution(name, yield* useScope()); + const resolution = imports.beginResolution(name); let identified; try { // The resolution this run opened is handed to identification rather @@ -2573,8 +2573,60 @@ function* executeDocument( identity.componentRouting.project, ); + /** + * Canonical resolution for one import, and the only thing that puts an + * invocation in one of this execution's identity domains. + * + * Held by the execution and handed to expansion by value. Expansion calls + * it as the terminal of a descriptor it created for one authored import, + * passing that import's own frame; the ordinary provider below calls it + * with no frame, for a direct `importComponent()` an invocation started + * itself. Neither path publishes the frame, and nothing outside core can + * name this operation. + */ + function* resolveCanonicalImport( + name: string, + position: Readonly | undefined, + selection: ImportSelection | undefined, + ): Operation { + // Read per import, in the invoking scope, so a component registered + // by a nested scope is visible to what that scope expands. + const registered = yield* Component.operations.registry; + const definition = yield* durableImportComponent( + name, + name === "__root__" ? root : undefined, + position, + { + searchPaths: includes, + registry: registered, + bundle, + declared: installedComponents, + catalog, + guarded: identity.protected, + }, + ); + // Canonical selection, recorded into the frame of the import that asked + // for it. This is the only thing that puts an invocation in one of this + // execution's identity domains: not the name, not the answer that comes + // back, and nothing a handler above this can hold + // (`invocation-identity.ts`). + if (definition.kind === "function") { + selection?.select(name, definition); + // The same record, for the other thing canonical resolution decides + // here: which dispatcher — if any — this import selected. A dispatcher + // a handler kept from another import reaches no body without it. + forms.select(name, definition); + } + // The witness for this answer. It is issued where the answer is + // produced and verified where it is invoked, so what a handler does to + // the value in between is visible rather than authoritative. + return imports === undefined ? definition : imports.issue(name, definition); + } + const environment: ExecutionEnvironment = { componentResolution: imports, + // Canonical resolution, for the terminal expansion builds per import. + canonicalImport: resolveCanonicalImport, // Everything this host declared, admitted above. Expansion asks it // about every name it reaches, which is how an installed construct is // dispatched without core holding a branch for its name. @@ -2613,42 +2665,31 @@ function* executeDocument( // and the root eval scope. yield* Component.around( { - *importComponent([name, position], _next) { - // Read per import, in the invoking scope, so a component registered - // by a nested scope is visible to what that scope expands. - const registered = yield* Component.operations.registry; - const definition = yield* durableImportComponent( - name, - name === "__root__" ? root : undefined, - position, - { - searchPaths: includes, - registry: registered, - bundle, - declared: installedComponents, - catalog, - guarded: identity.protected, - }, - ); - // Canonical selection, recorded where it is made. This is the only - // thing that puts an invocation in one of this execution's identity - // domains: not the name, not the answer that comes back, and - // nothing a handler above this can hold (`invocation-identity.ts`). - if (definition.kind === "function") { - // Recorded into the frame the scope that is resolving opened, - // rather than into whichever import happens to be innermost - // across the whole execution. - identity.identities.select(name, definition, yield* useScope()); - // The same record, for the other thing canonical resolution - // decides here: which dispatcher — if any — this import selected. - // A dispatcher a handler kept from another import reaches no body - // without it. - forms.select(name, definition); + *importComponent([name, position], next) { + // Delegation first. An authored import is asked through a descriptor + // that supplied a terminal of its own, so `next` answers it there — + // in that import's frame — and this provider is the middleware it + // composed through rather than the thing that resolved it. + try { + return yield* next(name, position); + } catch (error) { + // Only an empty public terminal reporting *this* name: nothing + // answered this call, so it is a direct `importComponent()` an + // invocation started for itself. It resolves ordinarily and names + // no frame, which is what makes it a separate import rather than a + // delegation of the authored one. Every other failure is somebody + // else's and propagates unchanged. + // + // The mark is parsed rather than the class compared: the terminal + // that raised it belongs to whichever copy of core built the + // descriptor that was asked, and a component loaded with + // `--include` or a middleware package holding its own copy is an + // ordinary arrangement, not a hypothetical. + if (!isMissingImportProvider(error, name)) { + throw error; + } + return yield* resolveCanonicalImport(name, position, undefined); } - // The witness for this answer. It is issued where the answer is - // produced and verified where it is invoked, so what a handler does - // to the value in between is visible rather than authoritative. - return imports === undefined ? definition : imports.issue(name, definition); }, *applyModifiers([modifiers, context], _next) { const chain = composeModifierChain(modifiers, context, registry); diff --git a/packages/core/src/execution-environment.ts b/packages/core/src/execution-environment.ts index 189b68944..cd44999be 100644 --- a/packages/core/src/execution-environment.ts +++ b/packages/core/src/execution-environment.ts @@ -30,9 +30,11 @@ import type { ComponentInvocation, ComponentRouting, FormSyntax, + ImportSelection, InvocationIdentities, } from "./invocation-identity.ts"; import type { ExactSource } from "./output/exact-source.ts"; +import type { ComponentDefinition, FunctionComponentDefinition, SourcePosition } from "./types.ts"; import type { SyntaxReference } from "./syntax-reference.ts"; /** @@ -98,6 +100,25 @@ export interface ExecutionEnvironment { * through this. */ readonly componentIdentity?: InvocationIdentities; + /** + * Canonical resolution for one import, as the execution performs it. + * + * Expansion calls this as the terminal of a descriptor it creates for one + * authored import, handing it that import's own frame — so the frame that + * receives the canonical selection is the one the element opened, whatever + * scope a handler delegated through. Absent where nothing canonical resolves + * imports, and then the public chain answers as it always did. + * + * Execution-owned and execution-private: it is on this by-value boundary + * beside component resolution, reaches no document, component or handler, and + * grants nothing by being here — what it decides is what canonical resolution + * decided anyway. + */ + readonly canonicalImport?: ( + name: string, + position: Readonly | undefined, + selection: ImportSelection | undefined, + ) => Operation; /** * Records which segments this execution produced as source rather than prose. * diff --git a/packages/core/src/expand.ts b/packages/core/src/expand.ts index 114a640fd..33d7b24b7 100644 --- a/packages/core/src/expand.ts +++ b/packages/core/src/expand.ts @@ -79,6 +79,7 @@ import { evalScope, handleFailure, importComponent, + importThroughTerminal, raise, } from "./component-api.ts"; import { @@ -2645,10 +2646,13 @@ function* expandComponent( // answered: what canonical resolution selected here is what decides whether // this invocation is in one of this execution's identity domains, and nothing // on the answer or in the chain carries it (`invocation-identity.ts`). - // Opened under the scope this expansion is running in, which is what makes - // the frame this spawn's own: a sibling `` resolving the same name at - // the same time opens its own, under its own scope. - const selection = environment?.componentIdentity?.beginImport(name, yield* useScope()); + // + // The frame is this dispatch's closure, and the terminal built for this one + // import is the only thing that can select into it. That is what makes it this + // invocation's own: a sibling `` resolving the same name at the same + // time has its own frame behind its own terminal, and a handler delegating + // through any number of descendant scopes still arrives at this one. + const selection = environment?.componentIdentity?.beginImport(name); let selected: IdentityDomain | undefined; let dispatcher: FunctionComponent | undefined; /** @@ -2673,8 +2677,19 @@ function* expandComponent( // whatever asks first, and authorizes only the answer it produced itself. const offered = environment?.installedComponents?.offer(environment.componentBodyScope, name); let answered: ImportedDefinition; + const canonical = environment?.canonicalImport; try { - answered = yield* importComponent(name, position); + // Through this import's own terminal when the execution has one: the + // public middleware chain composes around it by name, and `next` + // terminates in the continuation that carries this frame. Without an + // execution — inspection, a tool describing a document — the ordinary + // public operation answers exactly as it always did. + answered = + canonical === undefined + ? yield* importComponent(name, position) + : yield* importThroughTerminal(name, position, (asked, at) => + canonical(asked, at, selection), + ); } finally { offered?.close(); } diff --git a/packages/core/src/invocation-identity.ts b/packages/core/src/invocation-identity.ts index dec0d62c1..17432fd2b 100644 --- a/packages/core/src/invocation-identity.ts +++ b/packages/core/src/invocation-identity.ts @@ -391,34 +391,41 @@ export interface ProtectedDeclaration { */ export interface InvocationIdentities { /** - * Open the frame for one import the engine is about to ask for, under the - * engine scope that is asking. + * Open the frame for one import the engine is about to ask for. * - * The engine settles it as soon as that import answers, whatever the answer - * was, so nothing a handler does in between decides what the frame holds — - * including an import a sibling spawn opened while this one was in flight. + * The frame is a closure and nothing else: it is in no collection, under no + * key, and reachable only through the object this returns. The engine hands + * that object to the terminal it builds for this one import and settles it as + * soon as the import answers, however it answered — so nothing a handler does + * in between decides what the frame holds, and an import a sibling spawn + * opened at the same time is a different closure with a different terminal. */ - beginImport(name: string, scope: Scope): ImportSelection; - /** - * Record what canonical resolution selected. Only core's own resolver calls - * this, from inside the import the frame above was opened for, and under the - * same engine scope that opened it. - */ - select(name: string, definition: object, scope: Scope): void; + beginImport(name: string): ImportSelection; /** Answer for nothing, from here on. Called when the execution is torn down. */ revoke(): void; } /** One import's frame: what canonical resolution selected, once. */ export interface ImportSelection { + /** + * Record what canonical resolution selected for this import. + * + * Reachable only by holding this frame, which only the engine does: the + * terminal it builds for this import closes over it, and that terminal is + * what `next` reaches however many scopes a handler delegates through. A + * second selection in one frame is ambiguity rather than a correction, and + * settles to nothing. + */ + select(name: string, definition: object): void; /** * The domain of the registration canonical resolution selected here, if it * selected one of this execution's own. * * Answers `undefined` unless exactly one canonical resolution happened inside - * this frame, for the name the engine asked, selecting the implementation - * this execution built for that domain. A selection made in another scope's - * frame is not one that happened inside this one. + * this frame, for the name the engine asked, selecting the implementation this + * execution built for that domain. Idempotent: the frame closes the first time + * it is settled, and a selection after that is not one that happened inside + * it. */ settle(): IdentityDomain | undefined; } @@ -1142,88 +1149,60 @@ export function installIdentities( }); } - /** - * The import frames each Effection scope has open, innermost last. - * - * A stack per scope rather than one for the execution. Nesting inside one - * scope is still LIFO — a handler may expand something of its own while an - * import is in flight, and the inner import owns the top until it closes. - * What a single execution-wide stack could not express is *spawned - * concurrency*: two `` children may each have an import open at the - * same time, and whichever pushed last would then receive the other's - * canonical selection. - * One invocation would settle with no domain and the other with a domain it - * never selected, which is where an ordinary `` in each spawned child - * stopped being able to name its own durable identity. - * - * The scope is a private key and nothing else. It is never published, never - * read from, and never reaches a document, a component or a handler; two - * frames belong together because they were opened under the same engine - * scope object, not because of anything either of them says. - * - * Anything that leaves two selections in one frame — a handler delegating - * twice — still settles to nothing, which is the safe direction. - */ - const frames = new Map(); - return { identities: { - beginImport(asked: string, scope: Scope): ImportSelection { - const frame = { asked, selected: undefined as Minted | undefined, count: 0 }; - const open = frames.get(scope); - if (open === undefined) { - frames.set(scope, [frame]); - } else { - open.push(frame); - } + /** + * One import's frame, and the terminal that will select into it. + * + * No collection, no key, no stack: the frame is this closure, and the only + * way to select into it is to hold the object returned here. The engine + * hands it to the terminal it builds for this exact import, so a handler + * delegating through any number of descendant scopes still reaches *this* + * frame, and a sibling spawn resolving the same name at the same time + * reaches its own. Nothing about either frame is inferred from where it + * was opened or from what it resolved to. + */ + beginImport(asked: string): ImportSelection { + let selected: Minted | undefined; + let count = 0; + let closed = false; return { + select(name: string, definition: FunctionComponentDefinition): void { + // A frame the engine has already settled records nothing: the + // invocation it belonged to has its answer, and a selection arriving + // afterwards is another call's. + if (closed) { + return; + } + count += 1; + // The name canonical resolution answered for has to be the one the + // engine asked: a handler that delegates a different name selects a + // registration the element never named. + const domain = asked === name ? minted.get(name) : undefined; + // And the implementation has to be the one this execution built. A + // repository file, a nested registration and another execution's + // component all resolve to a different function. + selected = + domain !== undefined && domain.implementation === definition.fn ? domain : undefined; + }, settle(): IdentityDomain | undefined { - // Only this frame, and only from the scope that opened it: a sibling - // spawn closing its own import may neither clear this one nor be - // cleared by it. - const stack = frames.get(scope); - if (stack !== undefined) { - const index = stack.lastIndexOf(frame); - if (index >= 0) { - stack.splice(index, 1); - } - if (stack.length === 0) { - frames.delete(scope); - } + if (closed) { + return undefined; } - return frame.count === 1 && frame.selected !== undefined - ? frame.selected.domain - : undefined; + closed = true; + return count === 1 && selected !== undefined ? selected.domain : undefined; }, }; }, - select(name: string, definition: FunctionComponentDefinition, scope: Scope): void { - // The innermost import open in the scope that is resolving, which is - // the one this selection answers. A selection never reaches another - // spawn's frame, however the two happen to interleave. - const frame = frames.get(scope)?.at(-1); - if (frame === undefined) { - return; - } - frame.count += 1; - // The name canonical resolution answered for has to be the one the - // engine asked: a handler that delegates a different name selects a - // registration the element never named. - const domain = frame.asked === name ? minted.get(name) : undefined; - // And the implementation has to be the one this execution built. A - // repository file, a nested registration and another execution's - // component all resolve to a different function. - frame.selected = - domain !== undefined && domain.implementation === definition.fn ? domain : undefined; - }, revoke: () => { for (const domain of minted.values()) { domain.revoke(); } - // Every stack, not only the ones that emptied themselves: an execution - // torn down while a spawn still had an import open leaves no frame - // behind for anything to select into. - frames.clear(); + // There is no frame registry to clear. An execution torn down while a + // spawn still had an import open leaves that frame reachable only from + // the dispatch that owns it, and its domains answer for nothing from + // here — so a frame still in flight settles to nothing of its own + // accord. // The route goes with the domains: a wrapper projected into it, or a // route narrowed from it, answers for nothing once the execution that // minted the bodies is gone. diff --git a/packages/core/tests/all.test.ts b/packages/core/tests/all.test.ts index 63ae88daf..eeb35108e 100644 --- a/packages/core/tests/all.test.ts +++ b/packages/core/tests/all.test.ts @@ -41,7 +41,7 @@ import type { } from "../host.ts"; import { forEach } from "@effectionx/stream-helpers"; import { collect } from "../src/collect.ts"; -import { retain } from "../src/component-api.ts"; +import { Component, retain } from "../src/component-api.ts"; import { getExpansion } from "../src/expansion.ts"; import { retainedSource } from "../src/root-source.ts"; import { registerComponents } from "../src/components/registration.ts"; @@ -289,6 +289,7 @@ function run( stream?: InMemoryStream; files?: Record; drive?: (shared: Gated, stream: InMemoryStream) => Operation; + install?: () => Operation; } = {}, ): Operation { return scoped(function* () { @@ -298,6 +299,9 @@ function run( yield* useStubFs({ "test.md": source, ...options.files }); yield* useEchoExec(); yield* useComponents(shared); + if (options.install) { + yield* options.install(); + } if (options.drive) { yield* spawn(() => options.drive!(shared, stream)); } @@ -571,6 +575,162 @@ const COUNTER_DOC = [ "```", ].join("\n"); +/** + * Hold every import of `component` until `width` of them are live, then release + * them in `order`. + * + * The barrier is inside `importComponent` deliberately. `` holds a child in + * its component *body*, which its import has already finished by then — so two + * gated children prove the bodies overlapped, not the imports. Only a wait + * inside the import puts two of them in flight together, which is the one + * arrangement in which an import could take a sibling's canonical selection. + */ +function heldImports( + component: string, + width: number, + order: readonly number[], +): () => Operation { + const arrivals = Array.from({ length: width }, () => signal()); + const releases = Array.from({ length: width }, () => signal()); + let seen = 0; + return function* () { + yield* spawn(function* () { + for (const [index, arrival] of arrivals.entries()) { + yield* awaiting( + `the import of <${component}> number ${index + 1} starting`, + arrival.published, + ); + } + for (const index of order) { + releases[index].publish(); + } + }); + yield* Component.around( + { + *importComponent([name, position], next) { + if (name !== component || seen >= width) { + return yield* next(name, position); + } + const index = seen++; + arrivals[index].publish(); + yield* awaiting( + `the import of <${component}> number ${index + 1} being released`, + releases[index].published, + ); + return yield* next(name, position); + }, + }, + { at: "max" }, + ); + }; +} + +/** Two spawns, each held at its own gate and then naming its own identity. */ +const GATED_PROBES = [ + "", + '', + '', + "", + "", +].join("\n"); + +describe("Tier ALL — PA2: each concurrent site owns its own identity", () => { + beforeAll(() => useTempFileCompiler()); + + it("ALL3b: two concurrent authored sites each name their own identity, in either release order", function* () { + // Both children are held at their gates and then inside their own import, so + // the two imports are live at the same time. What this row holds is what the + // *document* decides under that overlap: which authored site each expansion + // identity belongs to, and that each site's component ran once. Where the + // canonical selection landed is CIV27's row, over declared components. + const first = harness(); + const forwards = yield* run(GATED_PROBES, { + shared: first, + // Both gates open first, and then both children suspend inside their own + // import until the other one is there too. + install: heldImports("Probe", 2, [0, 1]), + *drive(shared) { + yield* shared.arrival("one"); + yield* shared.arrival("two"); + shared.release("one"); + shared.release("two"); + }, + }); + expect(forwards.ok).toBe(true); + + const p1 = first.identities.get("p1"); + const p2 = first.identities.get("p2"); + expect(typeof p1).toBe("string"); + expect(typeof p2).toBe("string"); + expect(p1).not.toBe(p2); + // Each site claimed once. A frame that received a second selection would + // have settled to nothing and the invocation would name no identity at all. + expect(first.ran.filter((one) => one.startsWith("probe:"))).toEqual(["probe:p1", "probe:p2"]); + + // The same document, released in the opposite order. Ownership is the + // authored element's, so scheduling decides nothing about it. + const second = harness(); + const backwards = yield* run(GATED_PROBES, { + shared: second, + install: heldImports("Probe", 2, [1, 0]), + *drive(shared) { + yield* shared.arrival("one"); + yield* shared.arrival("two"); + shared.release("two"); + shared.release("one"); + }, + }); + expect(backwards.ok).toBe(true); + expect(second.identities.get("p1")).toBe(p1); + expect(second.identities.get("p2")).toBe(p2); + }); + + it("ALL3c: one child failing leaves the surviving sibling's own identity intact", function* () { + // One import is cancelled while the other is still live. There is no frame + // registry for a cancelled branch to leave behind, so the sibling that + // already claimed keeps exactly what it claimed. + const shared = harness(); + const result = yield* run( + [ + "", + '', + '', + "", + "", + ].join("\n"), + { + shared, + *drive(inner) { + yield* inner.arrival("one"); + yield* inner.arrival("two"); + // The survivor runs first, then the sibling fails under it. + inner.release("one"); + yield* inner.append("one"); + inner.release("two"); + }, + }, + ); + + expect(result.ok).toBe(false); + // The join published nothing, and the child that did run named its own + // identity rather than nothing or its sibling's. + const p1 = shared.identities.get("p1"); + expect(typeof p1).toBe("string"); + // The same identity that site names when nothing fails beside it: what the + // element is called its work after does not depend on a sibling at all. + const alone = harness(); + const quiet = yield* run(GATED_PROBES, { + shared: alone, + *drive(inner) { + inner.release("one"); + inner.release("two"); + }, + }); + expect(quiet.ok).toBe(true); + expect(p1).toBe(alone.identities.get("p1")); + }); +}); + describe("Tier ALL — PA3: counters, paths and the parent's own numbering", () => { beforeAll(() => useTempFileCompiler()); diff --git a/packages/core/tests/answer-identity.test.ts b/packages/core/tests/answer-identity.test.ts index b273d7a23..c793c0055 100644 --- a/packages/core/tests/answer-identity.test.ts +++ b/packages/core/tests/answer-identity.test.ts @@ -29,8 +29,8 @@ import { describe, it } from "@executablemd/test-support/bdd"; import { expect } from "@executablemd/test-support/expect"; -import { all, race, scoped, sleep, useScope, withResolvers } from "effection"; -import type { Operation, Scope } from "effection"; +import { scoped } from "effection"; +import type { Operation } from "effection"; import { AnswerIdentityError, @@ -51,83 +51,6 @@ const IDENTITY: AnswerIdentity = { origin: ORIGIN, key: "Open", revision: "1" }; const OPEN = { key: "Open", revision: "1" } as const; const OTHER = { key: "Other", revision: "1" } as const; -/** - * Where two sibling spawns wait for each other. - * - * A window belongs to the engine scope that opened it, so the rows about two - * spawns at once are written as two operations that each own their own scope and - * read it from inside. Nothing hands a `Scope` out of the operation that owns - * it, and a window never outlives the body that opened it. - * - * What is left is the coordination: both spawns have to be *open together*, - * which is the whole point, and neither may run ahead. Each step is a counter - * and one signal — the party that completes it releases everybody waiting on - * it, and a step that never completes is reported as a deadlock rather than - * waited on forever. - */ -function rendezvous(parties: number): (step: string) => Operation { - const steps = new Map(); - return function meet(step: string): Operation { - let slot = steps.get(step); - if (slot === undefined) { - slot = { arrived: 0, reached: signal() }; - steps.set(step, slot); - } - const waiting = slot; - return (function* () { - waiting.arrived += 1; - if (waiting.arrived >= parties) { - waiting.reached.publish(); - } - yield* awaiting(`both spawns reaching "${step}"`, waiting.reached.published); - })(); - }; -} - -/** - * How long a step a correct engine completes immediately may go uncompleted - * before the wait is called a deadlock. - * - * Never reached by a passing run: every step below is completed by the other - * spawn. It bounds only the failure mode, so a defect that stops one spawn - * says which step it stopped at instead of hanging the suite. - */ -const DEADLOCK_MS = 10_000; - -interface Signal { - publish(): void; - readonly published: Operation; -} - -function signal(): Signal { - const resolvers = withResolvers(); - let settled = false; - return { - publish() { - if (!settled) { - settled = true; - resolvers.resolve(true); - } - }, - get published() { - return resolvers.operation; - }, - }; -} - -function* awaiting(what: string, waited: Operation): Operation { - const reached = yield* race([ - waited, - (function* (): Operation { - yield* sleep(DEADLOCK_MS); - return false; - })(), - ]); - if (!reached) { - throw new Error(`${what} never happened`); - } -} - /** One owner, activated the way canonical execution activates it. */ function owner(): CanonicalImports { const imports = new CanonicalImports(); @@ -146,9 +69,8 @@ function resolving( imports: CanonicalImports, name: string, work: (resolution: ResolutionWindow) => T, - scope: Scope, ): T { - const resolution = imports.beginResolution(name, scope); + const resolution = imports.beginResolution(name); try { return work(resolution); } finally { @@ -167,9 +89,8 @@ function asking( installation: ProviderInstallation, name: string, work: (request: ComponentAnswerRequest) => T, - scope: Scope, ): T { - const asked = installation.open(scope, name); + const asked = installation.open(name); try { return work(asked.request); } finally { @@ -207,39 +128,27 @@ function refusalOf(attempt: () => unknown): unknown { describe("Tier CIV — an identity belongs to one answer of one import", () => { it("CIV23: an identity is stated on the exact answer and read back", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, supplied } = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - supplied: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), - }), - here, - ); + const { resolution, supplied } = resolving(imports, "Open", (resolution) => ({ + resolution, + supplied: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), + })); expect(imports.identify(resolution, supplied)?.identity).toEqual(IDENTITY); expect(identityRecord(IDENTITY)).toBe("test://provider#Open@1"); }); it("CIV24: identification answers with the claim-time copy, not the answer", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const supplied = answer(); - const resolution = resolving( - imports, - "Open", - (resolution) => { - asking(provider, "Open", (request) => request.claim(supplied, OPEN), here); - return resolution; - }, - here, - ); + const resolution = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => request.claim(supplied, OPEN)); + return resolution; + }); // One call answers both halves. The definition is core's own copy, taken // when the claim was recorded — so a caller that keeps what identification @@ -255,7 +164,6 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV24: an alternating answer cannot launder a copy through a second read", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const honest = answer(); @@ -275,15 +183,10 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }, }) as ImportedDefinition; - const resolution = resolving( - imports, - "Open", - (resolution) => { - asking(provider, "Open", (request) => request.claim(alternating, OPEN), here); - return resolution; - }, - here, - ); + const resolution = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => request.claim(alternating, OPEN)); + return resolution; + }); const identified = imports.identify(resolution, alternating); // The claim itself was recorded from the first reading, and identification @@ -298,81 +201,53 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: restating exactly the same claim is idempotent", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const supplied = answer(); - const resolution = resolving( - imports, - "Open", - (resolution) => { - asking( - provider, - "Open", - (request) => { - request.claim(supplied, OPEN); - // A provider installed twice states the same thing twice. That is not - // two providers disagreeing, and it is not a conflict. - expect(refusalOf(() => request.claim(supplied, OPEN))).toBe(undefined); - }, - here, - ); - return resolution; - }, - here, - ); + const resolution = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => { + request.claim(supplied, OPEN); + // A provider installed twice states the same thing twice. That is not + // two providers disagreeing, and it is not a conflict. + expect(refusalOf(() => request.claim(supplied, OPEN))).toBe(undefined); + }); + return resolution; + }); expect(imports.identify(resolution, supplied)?.identity).toEqual(IDENTITY); }); it("CIV23: a competing claim refuses and never overwrites the first", function* () { - const here = yield* useScope(); const imports = owner(); const first = imports.provider(ORIGIN); const second = imports.provider("test://other"); const held = answer(); - const resolution = resolving( - imports, - "Open", - (resolution) => { - asking(first, "Open", (request) => request.claim(held, OPEN), here); - // Another installation, asked in the same live resolution, cannot rename - // what the first stated. An overwrite would let a second provider take - // the first's implementation. - asking( - second, - "Open", - (request) => { - expect(refusalOf(() => request.claim(held, OPEN))).toBeInstanceOf(AnswerIdentityError); - }, - here, - ); - // And the first installation's *next* invocation cannot restate it - // differently either. - asking( - first, - "Open", - (request) => { - expect( - refusalOf(() => request.claim(held, { key: "Other", revision: "1" })), - ).toBeInstanceOf(AnswerIdentityError); - expect( - refusalOf(() => request.claim(held, { key: "Open", revision: "2" })), - ).toBeInstanceOf(AnswerIdentityError); - }, - here, + const resolution = resolving(imports, "Open", (resolution) => { + asking(first, "Open", (request) => request.claim(held, OPEN)); + // Another installation, asked in the same live resolution, cannot rename + // what the first stated. An overwrite would let a second provider take + // the first's implementation. + asking(second, "Open", (request) => { + expect(refusalOf(() => request.claim(held, OPEN))).toBeInstanceOf(AnswerIdentityError); + }); + // And the first installation's *next* invocation cannot restate it + // differently either. + asking(first, "Open", (request) => { + expect( + refusalOf(() => request.claim(held, { key: "Other", revision: "1" })), + ).toBeInstanceOf(AnswerIdentityError); + expect(refusalOf(() => request.claim(held, { key: "Open", revision: "2" }))).toBeInstanceOf( + AnswerIdentityError, ); - return resolution; - }, - here, - ); + }); + return resolution; + }); expect(imports.identify(resolution, held)?.identity).toEqual(IDENTITY); }); it("CIV25: a request whose handler has returned states nothing", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const late = answer(); @@ -383,34 +258,23 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { // the execution is still very much alive. What has ended is this // invocation, and an invocation that has returned is not supplying an // answer. - const resolution = resolving( - imports, - "Open", - (resolution) => { - asking( - provider, - "Open", - (request) => { - stale = request; - }, - here, - ); - expect(refusalOf(() => stale?.claim(late, OPEN))).toBeInstanceOf(AnswerIdentityError); - // The positive control in the same still-open window: a fresh invocation - // of the same installation claims, so the refusal above is about the - // handler lease rather than about the window or the provider. - asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); - return resolution; - }, - here, - ); + const resolution = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => { + stale = request; + }); + expect(refusalOf(() => stale?.claim(late, OPEN))).toBeInstanceOf(AnswerIdentityError); + // The positive control in the same still-open window: a fresh invocation + // of the same installation claims, so the refusal above is about the + // handler lease rather than about the window or the provider. + asking(provider, "Open", (request) => request.claim(answer(), OPEN)); + return resolution; + }); expect(imports.identify(resolution, late)).toBe(undefined); expect(imports.identifying).toBe(true); }); it("CIV25: a stale request cannot answer the next resolution of its own name", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const fresh = answer(); @@ -418,47 +282,27 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { let stale: ComponentAnswerRequest | undefined; // Resolution N of `Open`, whose handler keeps its request. - resolving( - imports, - "Open", - () => { - asking( - provider, - "Open", - (request) => { - requests.push(request); - stale = request; - }, - here, - ); - }, - here, - ); + resolving(imports, "Open", () => { + asking(provider, "Open", (request) => { + requests.push(request); + stale = request; + }); + }); // Resolution N+1 of the same name. The stale request names the right // component and belongs to an import that is over. - const { resolution, claimed } = resolving( - imports, - "Open", - (resolution) => { - expect(refusalOf(() => stale?.claim(fresh, OPEN))).toBeInstanceOf(AnswerIdentityError); - // The same installation is asked again and answers this resolution: the - // installation is reusable, the request is not. - return { - resolution, - claimed: asking( - provider, - "Open", - (request) => { - requests.push(request); - return request.claim(answer(), OPEN); - }, - here, - ), - }; - }, - here, - ); + const { resolution, claimed } = resolving(imports, "Open", (resolution) => { + expect(refusalOf(() => stale?.claim(fresh, OPEN))).toBeInstanceOf(AnswerIdentityError); + // The same installation is asked again and answers this resolution: the + // installation is reusable, the request is not. + return { + resolution, + claimed: asking(provider, "Open", (request) => { + requests.push(request); + return request.claim(answer(), OPEN); + }), + }; + }); expect(requests).toHaveLength(2); expect(requests[0]).not.toBe(requests[1]); @@ -467,57 +311,33 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: a stale request cannot retag while another name is being decided", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const substitute = answer("Other"); let stale: ComponentAnswerRequest | undefined; - resolving( - imports, - "Open", - () => { - asking( - provider, - "Open", - (request) => { - stale = request; - }, - here, - ); - }, - here, - ); + resolving(imports, "Open", () => { + asking(provider, "Open", (request) => { + stale = request; + }); + }); // `claim` takes no name, so the stale request cannot even ask about the // name being decided: it is fixed to `Open`, which this resolution is not. - const { resolution, claimed } = resolving( - imports, - "Other", - (resolution) => { - expect(stale?.name).toBe("Open"); - expect(refusalOf(() => stale?.claim(substitute, OTHER))).toBeInstanceOf( - AnswerIdentityError, - ); - return { - resolution, - claimed: asking( - provider, - "Other", - (request) => request.claim(answer("Other"), OTHER), - here, - ), - }; - }, - here, - ); + const { resolution, claimed } = resolving(imports, "Other", (resolution) => { + expect(stale?.name).toBe("Open"); + expect(refusalOf(() => stale?.claim(substitute, OTHER))).toBeInstanceOf(AnswerIdentityError); + return { + resolution, + claimed: asking(provider, "Other", (request) => request.claim(answer("Other"), OTHER)), + }; + }); expect(imports.identify(resolution, substitute)).toBe(undefined); expect(imports.identify(resolution, claimed)?.identity.key).toBe("Other"); }); it("CIV25: one installation answers two names through two distinct requests", function* () { - const here = yield* useScope(); const imports = owner(); // One installation owns one origin and may answer more than one admitted // name. Spending the installation on its first answer would break exactly @@ -525,40 +345,20 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { const provider = imports.provider(ORIGIN); const seen: ComponentAnswerRequest[] = []; - const open = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - claimed: asking( - provider, - "Open", - (request) => { - seen.push(request); - return request.claim(answer(), OPEN); - }, - here, - ), + const open = resolving(imports, "Open", (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => { + seen.push(request); + return request.claim(answer(), OPEN); }), - here, - ); - const other = resolving( - imports, - "Other", - (resolution) => ({ - resolution, - claimed: asking( - provider, - "Other", - (request) => { - seen.push(request); - return request.claim(answer("Other"), OTHER); - }, - here, - ), + })); + const other = resolving(imports, "Other", (resolution) => ({ + resolution, + claimed: asking(provider, "Other", (request) => { + seen.push(request); + return request.claim(answer("Other"), OTHER); }), - here, - ); + })); // Two invocations, two requests, each fixed to what it was asked. expect(seen).toHaveLength(2); @@ -569,45 +369,24 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: identification takes the window it was asked about", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const requests: ComponentAnswerRequest[] = []; - const first = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - claimed: asking( - provider, - "Open", - (request) => { - requests.push(request); - return request.claim(answer(), OPEN); - }, - here, - ), + const first = resolving(imports, "Open", (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => { + requests.push(request); + return request.claim(answer(), OPEN); }), - here, - ); - const second = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - claimed: asking( - provider, - "Open", - (request) => { - requests.push(request); - return request.claim(answer(), OPEN); - }, - here, - ), + })); + const second = resolving(imports, "Open", (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => { + requests.push(request); + return request.claim(answer(), OPEN); }), - here, - ); + })); // Each answer belongs to the import it answered, and to no other. Nothing // here reads whichever window is current: the caller presents the one it @@ -621,54 +400,42 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: a request shows the asked position by value", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); // The engine's own object, which it reads again after any handler has seen // it. A provider is shown a copy, like everything else it is shown. const scanned = { path: "doc.md", offset: 12, line: 3, column: 5 }; - resolving( - imports, - "Open", - () => { - const asked = provider.open(here, "Open", scanned); - try { - const shown = asked.request.position; - expect(shown).toEqual(scanned); - expect(shown).not.toBe(scanned); - // Editing what the handler was given reaches nothing, and the request - // itself cannot be re-pointed at another element. - expect(() => { - (shown as { line: number }).line = 99; - }).toThrow(); - expect(() => { - (asked.request as { name: string }).name = "Other"; - }).toThrow(); - } finally { - asked.close(); - } - // And the engine's own object is untouched by having been shown. - expect(scanned).toEqual({ path: "doc.md", offset: 12, line: 3, column: 5 }); - }, - here, - ); + resolving(imports, "Open", () => { + const asked = provider.open("Open", scanned); + try { + const shown = asked.request.position; + expect(shown).toEqual(scanned); + expect(shown).not.toBe(scanned); + // Editing what the handler was given reaches nothing, and the request + // itself cannot be re-pointed at another element. + expect(() => { + (shown as { line: number }).line = 99; + }).toThrow(); + expect(() => { + (asked.request as { name: string }).name = "Other"; + }).toThrow(); + } finally { + asked.close(); + } + // And the engine's own object is untouched by having been shown. + expect(scanned).toEqual({ path: "doc.md", offset: 12, line: 3, column: 5 }); + }); }); it("CIV23: a different object carries no claim, however alike", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, claimed } = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), - }), - here, - ); + const { resolution, claimed } = resolving(imports, "Open", (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), + })); expect(imports.identify(resolution, claimed)?.identity).toEqual(IDENTITY); // The outer-replacement case: a handler further out returns its own object, @@ -679,19 +446,13 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: editing the claimed answer invalidates the claim", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, claimed } = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), - }), - here, - ); + const { resolution, claimed } = resolving(imports, "Open", (resolution) => ({ + resolution, + claimed: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), + })); expect(imports.identify(resolution, claimed)?.identity).toEqual(IDENTITY); // The same object, edited after the claim by a handler further out. What @@ -702,29 +463,21 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: an installation retained past its execution opens nothing", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); - const { resolution, before } = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - before: asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), - }), - here, - ); + const { resolution, before } = resolving(imports, "Open", (resolution) => ({ + resolution, + before: asking(provider, "Open", (request) => request.claim(answer(), OPEN)), + })); expect(imports.identify(resolution, before)?.identity).toEqual(IDENTITY); imports.revoke(); // The installation is the object a provider kept. The window it would need // cannot be opened, and a request minted from it states nothing. - expect(refusalOf(() => imports.beginResolution("Open", here))).toBeInstanceOf( - AnswerIdentityError, - ); + expect(refusalOf(() => imports.beginResolution("Open"))).toBeInstanceOf(AnswerIdentityError); expect( - refusalOf(() => asking(provider, "Open", (request) => request.claim(answer(), OPEN), here)), + refusalOf(() => asking(provider, "Open", (request) => request.claim(answer(), OPEN))), ).toBeInstanceOf(AnswerIdentityError); // And what it stated while the execution was live identifies nothing now: // an admission may not be reconciled against a run that is over. @@ -733,53 +486,36 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV25: an owner starts inactive, so a claim before activation refuses", function* () { - const here = yield* useScope(); const imports = new CanonicalImports(); // Canonical execution registers teardown, then activates, then installs // providers. A claim that landed before activation would be a claim with no // teardown behind it. expect(imports.identifying).toBe(false); - expect(refusalOf(() => imports.beginResolution("Open", here))).toBeInstanceOf( - AnswerIdentityError, - ); + expect(refusalOf(() => imports.beginResolution("Open"))).toBeInstanceOf(AnswerIdentityError); expect( refusalOf(() => - asking(imports.provider(ORIGIN), "Open", (request) => request.claim(answer(), OPEN), here), + asking(imports.provider(ORIGIN), "Open", (request) => request.claim(answer(), OPEN)), ), ).toBeInstanceOf(AnswerIdentityError); }); it("CIV25: overlapping executions are isolated", function* () { - const here = yield* useScope(); const first = owner(); const second = owner(); const shared = answer(); - const one = resolving( - first, - "Open", - (resolution) => { - asking(first.provider(ORIGIN), "Open", (request) => request.claim(shared, OPEN), here); - return resolution; - }, - here, - ); + const one = resolving(first, "Open", (resolution) => { + asking(first.provider(ORIGIN), "Open", (request) => request.claim(shared, OPEN)); + return resolution; + }); // Live at the same time, and each answers only for what it recorded. - const two = resolving( - second, - "Open", - (resolution) => { - expect(second.identify(resolution, shared)).toBe(undefined); - asking( - second.provider(ORIGIN), - "Open", - (request) => request.claim(shared, { key: "Open", revision: "2" }), - here, - ); - return resolution; - }, - here, - ); + const two = resolving(second, "Open", (resolution) => { + expect(second.identify(resolution, shared)).toBe(undefined); + asking(second.provider(ORIGIN), "Open", (request) => + request.claim(shared, { key: "Open", revision: "2" }), + ); + return resolution; + }); expect(first.identify(one, shared)?.identity).toEqual(IDENTITY); expect(second.identify(two, shared)?.identity).toEqual({ @@ -795,30 +531,20 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: a provider cannot state an origin canonical execution did not give it", function* () { - const here = yield* useScope(); const imports = owner(); // The installation carries the origin; the provider states only key and // revision. There is no member on the claim call to put another origin in. - const { resolution, claimed } = resolving( - imports, - "Open", - (resolution) => ({ - resolution, - claimed: asking( - imports.provider("test://assigned"), - "Open", - (request) => request.claim(answer(), OPEN), - here, - ), - }), - here, - ); + const { resolution, claimed } = resolving(imports, "Open", (resolution) => ({ + resolution, + claimed: asking(imports.provider("test://assigned"), "Open", (request) => + request.claim(answer(), OPEN), + ), + })); expect(imports.identify(resolution, claimed)?.identity.origin).toBe("test://assigned"); }); it("CIV23: a partial identity is refused rather than recorded", function* () { - const here = yield* useScope(); const imports = owner(); const provider = imports.provider(ORIGIN); const attempts = [ @@ -828,24 +554,14 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { for (const attempt of attempts) { const supplied = answer(); - const resolution = resolving( - imports, - "Open", - (resolution) => { - asking( - provider, - "Open", - (request) => { - expect(refusalOf(() => request.claim(supplied, attempt))).toBeInstanceOf( - AnswerIdentityError, - ); - }, - here, + const resolution = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => { + expect(refusalOf(() => request.claim(supplied, attempt))).toBeInstanceOf( + AnswerIdentityError, ); - return resolution; - }, - here, - ); + }); + return resolution; + }); // Refused rather than partially recorded: a half identity would compare // equal to a different half identity. expect(imports.identify(resolution, supplied)).toBe(undefined); @@ -853,22 +569,16 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { }); it("CIV23: an answer nobody claimed identifies nothing", function* () { - const here = yield* useScope(); const imports = owner(); // The ordinary case, and the reason this is not a permission: an unidentified // answer is a perfectly good answer. What it cannot be is the thing a // fragment runs, because a continuation would have nothing to compare. - resolving( - imports, - "Open", - (resolution) => { - expect(imports.identify(resolution, answer())).toBe(undefined); - expect(imports.identify(resolution, undefined)).toBe(undefined); - expect(imports.identify(resolution, null)).toBe(undefined); - expect(imports.identify(resolution, "Open")).toBe(undefined); - }, - here, - ); + resolving(imports, "Open", (resolution) => { + expect(imports.identify(resolution, answer())).toBe(undefined); + expect(imports.identify(resolution, undefined)).toBe(undefined); + expect(imports.identify(resolution, null)).toBe(undefined); + expect(imports.identify(resolution, "Open")).toBe(undefined); + }); }); }); @@ -882,254 +592,93 @@ describe("Tier CIV — an identity belongs to one answer of one import", () => { * scopes standing for two spawns, and never with one spawn's bookkeeping * standing in for the other's. */ -describe("Tier PA10b — concurrent resolution windows", () => { - it("PA10b: one installation answers two windows open at the same time", function* () { - const imports = owner(); - const provider = imports.provider(ORIGIN); - const meet = rendezvous(2); - const answers = new Map(); - - /** - * One spawned child, resolving in a scope of its own. - * - * Everything the spawn owns is opened and settled inside this operation: - * it reads its own scope here, keeps its window and its request for as long - * as the operation lasts, and hands nothing but its answer back. The two - * run together under `all`, held at a rendezvous so neither can finish - * before the other has opened — which is what makes two windows genuinely - * open at once rather than one after the other. - */ - const resolve = (name: string) => - scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - // Both windows are open before either spawn claims, which is the - // shape two `` children produce and the only arrangement in - // which a claim could land in the wrong one. - yield* meet("both open"); - answers.set( - name, - asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), - ); - yield* meet("claimed"); - // Both spawns have answered and both windows are still open, so - // the cross-checks are made while the other one really exists. - const mine = answers.get(name)!; - const other = answers.get(name === "left" ? "right" : "left")!; - expect(imports.identify(window, mine)?.identity).toEqual(IDENTITY); - expect(imports.identify(window, other)).toBe(undefined); - yield* meet("checked"); - } finally { - window.close(); - } - }); - - yield* all([resolve("left"), resolve("right")]); - // Two distinct answers, neither overwritten by the other's claim. - expect(answers.size).toBe(2); - expect(answers.get("left")).not.toBe(answers.get("right")); - }); - - it("PA10b: a request answers its own spawn and refuses the sibling's", function* () { +describe("Tier PA10b — one serial resolution window", () => { + /** + * Component answers are captured serially, before any document expands. + * + * That is the whole reason no scope takes part here: the execution asks for + * each admitted name in turn, so there is one window at a time, and what a + * request answers is the window object it captured when its handler was + * opened — not whichever window is open when it happens to claim, and not + * anything about where it is running. + */ + it("PA10b: a request answers the window it captured, not the one open later", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); - const meet = rendezvous(2); - const mine = scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - const kept = provider.open(here, "Open"); - // Held open while the sibling's window is the last one opened anywhere. - // Being the most recent window in the execution is not being the window - // this handler was asked in. - yield* meet("both open"); - expect(imports.identify(window, kept.request.claim(answer(), OPEN))?.identity).toEqual( - IDENTITY, - ); - kept.close(); - // And once closed it answers nothing at all. - expect(refusalOf(() => kept.request.claim(answer(), OPEN))).toBeInstanceOf( - AnswerIdentityError, - ); - yield* meet("done"); - } finally { - window.close(); - } - }); - - const sibling = scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - yield* meet("both open"); - yield* meet("done"); - } finally { - window.close(); - } - }); - - yield* all([mine, sibling]); + const first = imports.beginResolution("Open"); + const kept = provider.open("Open"); + // The capture phase moves on: this resolution closes and the next name's + // window opens. The request is still holding the first one. + first.close(); + const second = imports.beginResolution("Open"); + try { + expect(refusalOf(() => kept.request.claim(answer(), OPEN))).toBeInstanceOf( + AnswerIdentityError, + ); + // And the window that is open answers for what was claimed in it. + const claimed = asking(provider, "Open", (request) => request.claim(answer(), OPEN)); + expect(imports.identify(second, claimed)?.identity).toEqual(IDENTITY); + } finally { + kept.close(); + second.close(); + } }); - it("PA10b: a second different answer in one window refuses, whatever the sibling did", function* () { + it("PA10b: a handler that delegates through a descendant scope still identifies", function* () { + // The request captured its window before the handler ran, so a handler that + // does its work in a scope of its own answers the same resolution. Nothing + // about the scope participates in the correlation. const imports = owner(); const provider = imports.provider(ORIGIN); - const meet = rendezvous(2); - const refused: unknown[] = []; - - const first = scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); - // The sibling answers in between, which is what an installation that - // remembered only its most recent window would treat as un-spending - // this one. - yield* meet("answered once"); - yield* meet("sibling answered"); - refused.push( - refusalOf(() => - asking(provider, "Open", (request) => request.claim(answer(), OPEN), here), - ), - ); - } finally { - window.close(); - } - }); - const other = scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - yield* meet("answered once"); - asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); - yield* meet("sibling answered"); - } finally { - window.close(); - } - }); - - yield* all([first, other]); - expect(refused).toHaveLength(1); - expect(refused[0]).toBeInstanceOf(AnswerIdentityError); + const window = imports.beginResolution("Open"); + try { + const claimed = yield* scoped(function* (): Operation { + return asking(provider, "Open", (request) => request.claim(answer(), OPEN)); + }); + expect(imports.identify(window, claimed)?.identity).toEqual(IDENTITY); + } finally { + window.close(); + } }); - it("PA10b: one spawn ending leaves the other live, and teardown leaves neither", function* () { + it("PA10b: with no window open, a provider answers and identifies nothing", function* () { + // Where concurrent document imports are: after capture, with no profile + // window open at all. A handler may still answer such an import as ordinary + // middleware; what it cannot do is acquire a profile identity for it. const imports = owner(); const provider = imports.provider(ORIGIN); - const meet = rendezvous(2); - const identified: unknown[] = []; - - // This spawn simply ends, which is what a spawned child answering, failing - // or being cancelled looks like from the owner's side: its scope goes, and - // with it every window it had open. - const ending = scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - yield* meet("both open"); - } finally { - window.close(); - } - }); - - const continuing = scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - yield* meet("both open"); - yield* meet("the other ended"); - // Still deciding, and still claimable: the spawn that ended neither - // cleared this window nor authorized anything in it. - const still = asking(provider, "Open", (request) => request.claim(answer(), OPEN), here); - identified.push(imports.identify(window, still)?.identity); - } finally { - window.close(); - } - }); - yield* all([ - (function* (): Operation { - yield* ending; - yield* meet("the other ended"); - })(), - continuing, - ]); - expect(identified).toEqual([IDENTITY]); - - // And once the owner is torn down nothing may be resolved at all, in any - // scope — asked inside an operation that owns the scope it asks with. - yield* scoped(function* () { - const here = yield* useScope(); - imports.revoke(); - expect(refusalOf(() => imports.beginResolution("Open", here))).toBeInstanceOf( - AnswerIdentityError, - ); - }); - }); - - it("PA10b: a nested resolution owns the top of its own spawn until it closes", function* () { - const imports = owner(); - const provider = imports.provider(ORIGIN); + const window = imports.beginResolution("Open"); + window.close(); - yield* scoped(function* () { - const here = yield* useScope(); - const outer = imports.beginResolution("Open", here); - const held = provider.open(here, "Open"); - // The nested resolution is for the *same* name, which is the case a check - // written against the name rather than the exact window would admit. - const inner = imports.beginResolution("Open", here); - // The inner resolution hides its parent: a request minted for the outer - // one states nothing while something nested is deciding. - expect(refusalOf(() => held.request.claim(answer(), OPEN))).toBeInstanceOf( - AnswerIdentityError, - ); - inner.close(); - // And the parent is claimable again once the nested one is over. - const supplied = held.request.claim(answer(), OPEN); - expect(imports.identify(outer, supplied)?.identity).toEqual(IDENTITY); - held.close(); - outer.close(); - }); + expect( + refusalOf(() => asking(provider, "Open", (request) => request.claim(answer(), OPEN))), + ).toBeInstanceOf(AnswerIdentityError); + expect(imports.identify(window, answer())).toBe(undefined); }); }); -/** - * Tier PA10c — one reusable provider, one definition, several imports. - * - * A provider that holds an immutable definition hands back the exact same object - * every time it answers. What that object *is* was settled once; which import it - * answered is settled per resolution. These rows use one shared reference, - * created once, so a ledger that made the first window part of the object's - * permanent claim refuses the second — which is the defect they exist to catch. - */ describe("Tier PA10c — one definition answering more than one import", () => { it("PA10c: the same definition answers a later import after the first window closed", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); - const here = yield* useScope(); // One object, created once and never copied: this is what a provider that // owns its definition hands to everybody who asks. const shared = answer(); - const first = resolving( - imports, - "Open", - (resolution) => { - const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN), here); - expect(supplied).toBe(shared); - expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); - return resolution; - }, - here, - ); + const first = resolving(imports, "Open", (resolution) => { + const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN)); + expect(supplied).toBe(shared); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + return resolution; + }); // The second import is a new resolution of the same name, after the first is // over. The definition is the same object, and it is still this provider's // answer to say. - resolvingLater(imports, provider, here, shared); + resolvingLater(imports, provider, shared); // And the closed window still reads the claim it recorded, unchanged by the // later one: each resolution keeps its own. expect(imports.identify(first, shared)?.identity).toEqual(IDENTITY); @@ -1138,7 +687,6 @@ describe("Tier PA10c — one definition answering more than one import", () => { it("PA10c: reuse cannot substitute between comparison and retention", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); - const here = yield* useScope(); const reads: string[] = []; const shared = new Proxy(answer(), { get(target, key, receiver) { @@ -1157,200 +705,119 @@ describe("Tier PA10c — one definition answering more than one import", () => { }, }); - const first = resolving( - imports, - "Open", - (resolution) => { - asking(provider, "Open", (request) => request.claim(shared, OPEN), here); - return resolution; - }, - here, - ); + const first = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => request.claim(shared, OPEN)); + return resolution; + }); expect(imports.identify(first, shared)?.definition.name).toBe("Open"); - resolving( - imports, - "Open", - (resolution) => { - asking( - provider, - "Open", - (request) => { - expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf( - AnswerIdentityError, - ); - return undefined; - }, - here, - ); - expect(imports.identify(resolution, shared)).toBe(undefined); - }, - here, - ); + resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => { + expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf(AnswerIdentityError); + return undefined; + }); + expect(imports.identify(resolution, shared)).toBe(undefined); + }); }); it("PA10c: an edited definition cannot be claimed again, and identifies nowhere", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); - const here = yield* useScope(); const shared = answer(); - const first = resolving( - imports, - "Open", - (resolution) => { - asking(provider, "Open", (request) => request.claim(shared, OPEN), here); - expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); - return resolution; - }, - here, - ); + const first = resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => request.claim(shared, OPEN)); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + return resolution; + }); // One member of the definition, edited after it was claimed and while the // stated identity says nothing changed. This is a different implementation // wearing the first one's revision. shared.props = { type: "object", properties: {}, additionalProperties: true }; - resolving( - imports, - "Open", - (resolution) => { - asking( - provider, - "Open", - (request) => { - // Refused before anything is recorded: the identity was stated about - // the definition core retained, and this object is no longer it. - expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf( - AnswerIdentityError, - ); - return undefined; - }, - here, - ); - // So the new window vouches for nothing. - expect(imports.identify(resolution, shared)).toBe(undefined); - }, - here, - ); + resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => { + // Refused before anything is recorded: the identity was stated about + // the definition core retained, and this object is no longer it. + expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf(AnswerIdentityError); + return undefined; + }); + // So the new window vouches for nothing. + expect(imports.identify(resolution, shared)).toBe(undefined); + }); // And the window that did claim it cannot identify the changed object // either, which is the change detection that was already there. expect(imports.identify(first, shared)).toBe(undefined); }); - it("PA10c: the same definition answers two imports open at the same time", function* () { + it("PA10c: one definition answers two windows in turn, and each holds its own copy", function* () { + // Serial, because capture is: the first resolution closes before the second + // opens. What this holds is that reuse is per window — the second window + // identifies the same definition, and closing either leaves the other's copy + // alone. const imports = owner(); const provider = imports.provider(ORIGIN); - const meet = rendezvous(2); const shared = answer(); - const identified = new Map(); - - /** One spawned child's import, opened and settled inside its own operation. */ - const resolve = (name: string) => - scoped(function* (): Operation { - const here = yield* useScope(); - const window = imports.beginResolution("Open", here); - try { - // Both windows are open before either claims, so neither claim can be - // the other's: this is the arrangement sibling spawns produce. - yield* meet("both open"); - const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN), here); - // The provider handed back its own object, not a copy of it. - expect(supplied).toBe(shared); - yield* meet("claimed"); - // Read while the sibling's window is still open, which is the only - // arrangement in which a shared ledger entry could answer for the - // wrong import. - identified.set(name, imports.identify(window, shared)?.identity); - yield* meet("checked"); - } finally { - window.close(); - } - }); - yield* all([resolve("left"), resolve("right")]); - expect(identified.get("left")).toEqual(IDENTITY); - expect(identified.get("right")).toEqual(IDENTITY); + const first = imports.beginResolution("Open"); + asking(provider, "Open", (request) => request.claim(shared, OPEN)); + expect(imports.identify(first, shared)?.identity).toEqual(IDENTITY); + first.close(); + + const second = imports.beginResolution("Open"); + try { + asking(provider, "Open", (request) => request.claim(shared, OPEN)); + expect(imports.identify(second, shared)?.identity).toEqual(IDENTITY); + // And each window keeps its own copy: the first still identifies what it + // claimed, because provenance is a fact about that resolution rather than + // about which one is open now. + expect(imports.identify(first, shared)?.identity).toEqual(IDENTITY); + } finally { + second.close(); + } }); it("PA10c: reuse spends each window, so a different answer in one still refuses", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); - const here = yield* useScope(); const shared = answer(); - resolvingLater(imports, provider, here, shared); + resolvingLater(imports, provider, shared); // The same definition again in a fresh window is reuse; a *second* answer in // that same window is two answers to one import, and that still refuses. - resolving( - imports, - "Open", - (resolution) => { - asking( - provider, - "Open", - (request) => { - expect(request.claim(shared, OPEN)).toBe(shared); - expect(refusalOf(() => request.claim(answer(), OPEN))).toBeInstanceOf( - AnswerIdentityError, - ); - return undefined; - }, - here, - ); - expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); - }, - here, - ); + resolving(imports, "Open", (resolution) => { + asking(provider, "Open", (request) => { + expect(request.claim(shared, OPEN)).toBe(shared); + expect(refusalOf(() => request.claim(answer(), OPEN))).toBeInstanceOf(AnswerIdentityError); + return undefined; + }); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + }); }); it("PA10c: a new window cannot rename the definition or take it for another provider", function* () { const imports = owner(); const provider = imports.provider(ORIGIN); const other = imports.provider("test://other"); - const here = yield* useScope(); const shared = answer(); - resolvingLater(imports, provider, here, shared); + resolvingLater(imports, provider, shared); // What this object is was settled by its first claim. A new resolution is a // new question about which import it answered, never a chance to restate it. - resolving( - imports, - "Other", - (resolution) => { - asking( - provider, - "Other", - (request) => { - expect(refusalOf(() => request.claim(shared, OTHER))).toBeInstanceOf( - AnswerIdentityError, - ); - return undefined; - }, - here, - ); - expect(imports.identify(resolution, shared)).toBe(undefined); - }, - here, - ); - resolving( - imports, - "Open", - (resolution) => { - asking( - other, - "Open", - (request) => { - expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf( - AnswerIdentityError, - ); - return undefined; - }, - here, - ); - expect(imports.identify(resolution, shared)).toBe(undefined); - }, - here, - ); + resolving(imports, "Other", (resolution) => { + asking(provider, "Other", (request) => { + expect(refusalOf(() => request.claim(shared, OTHER))).toBeInstanceOf(AnswerIdentityError); + return undefined; + }); + expect(imports.identify(resolution, shared)).toBe(undefined); + }); + resolving(imports, "Open", (resolution) => { + asking(other, "Open", (request) => { + expect(refusalOf(() => request.claim(shared, OPEN))).toBeInstanceOf(AnswerIdentityError); + return undefined; + }); + expect(imports.identify(resolution, shared)).toBe(undefined); + }); }); }); @@ -1365,17 +832,11 @@ describe("Tier PA10c — one definition answering more than one import", () => { function resolvingLater( imports: CanonicalImports, provider: ProviderInstallation, - scope: Scope, shared: ImportedDefinition, ): void { - resolving( - imports, - "Open", - (resolution) => { - const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN), scope); - expect(supplied).toBe(shared); - expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); - }, - scope, - ); + resolving(imports, "Open", (resolution) => { + const supplied = asking(provider, "Open", (request) => request.claim(shared, OPEN)); + expect(supplied).toBe(shared); + expect(imports.identify(resolution, shared)?.identity).toEqual(IDENTITY); + }); } diff --git a/packages/core/tests/declared-markdown-component.test.ts b/packages/core/tests/declared-markdown-component.test.ts index 282e3edf5..454007839 100644 --- a/packages/core/tests/declared-markdown-component.test.ts +++ b/packages/core/tests/declared-markdown-component.test.ts @@ -36,7 +36,7 @@ import { API } from "@executablemd/runtime"; import { mkdir, mkdtemp, realpath } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { InMemoryStream } from "@executablemd/durable-streams"; +import { InMemoryStream, StaleInputError } from "@executablemd/durable-streams"; import type { DurableEvent, Json } from "@executablemd/durable-streams"; import { Component } from "../src/component-api.ts"; import { collect } from "../src/collect.ts"; @@ -1390,8 +1390,9 @@ function* published( declarations: readonly MarkdownComponent[], extra: readonly ExecutionInstallation[], stream: InMemoryStream = new InMemoryStream(), + /** Where each published chunk lands, so a failed run's output is still readable. */ + chunks: string[] = [], ): Operation { - const chunks: string[] = []; return yield* scoped(function* () { yield* useNormalizedOutput(); yield* useTerminalOutput(); @@ -1434,17 +1435,25 @@ function answeringOpenName(definition: ImportedDefinition): ExecutionInstallatio }; } -/** One replay that is expected to refuse, with whatever it managed to publish. */ +/** + * One replay that is expected to refuse, with whatever it published on the way. + * + * The chunks are the caller's array, so what this reports is what the run + * actually handed the Output Api before it failed — not an empty string this + * helper decided on. A row asserting "published nothing" has to be able to see + * something. + */ function* refusalOfRun( source: string, declarations: readonly MarkdownComponent[], history: readonly DurableEvent[], -): Operation<{ failed: boolean; output: string }> { +): Operation<{ failure: unknown; output: string }> { + const chunks: string[] = []; try { - const output = yield* published(source, declarations, [], new InMemoryStream([...history])); - return { failed: false, output }; - } catch { - return { failed: true, output: "" }; + yield* published(source, declarations, [], new InMemoryStream([...history]), chunks); + return { failure: undefined, output: chunks.join("") }; + } catch (error) { + return { failure: error, output: chunks.join("") }; } } @@ -1634,7 +1643,6 @@ describe("Tier DM — exact source is a provenance, not a field", () => { (event) => event.type === "close" && event.coroutineId.includes("."), ); expect(children).toHaveLength(2); - // What each child retained says what its bytes were, not only what they said. // What each child retained says what its bytes were, not only what they // said. Read as a set: children close in whatever order they finished, and // which one finished first is exactly what this must not depend on. @@ -1688,12 +1696,14 @@ describe("Tier DM — exact source is a provenance, not a field", () => { ? { ...event, result: { status: "ok" as const, value } } : event, ); - const published_ = yield* refusalOfRun(source, declarations, history); - - // Refused, and nothing published: a document rebuilt without the part it - // could not read is a document that never existed. - expect([JSON.stringify(value), published_.failed]).toEqual([JSON.stringify(value), true]); - expect([JSON.stringify(value), published_.output]).toEqual([JSON.stringify(value), ""]); + const attempt = yield* refusalOfRun(source, declarations, history); + const which = JSON.stringify(value); + + // Refused as the stale input it is, and nothing published on the way: a + // document rebuilt without the part it could not read is a document that + // never existed. The chunks are the run's own, collected before it failed. + expect([which, attempt.failure instanceof StaleInputError]).toEqual([which, true]); + expect([which, attempt.output]).toEqual([which, ""]); } }); }); diff --git a/packages/core/tests/invocation-identity.test.ts b/packages/core/tests/invocation-identity.test.ts index d37cf2808..88c58d3a9 100644 --- a/packages/core/tests/invocation-identity.test.ts +++ b/packages/core/tests/invocation-identity.test.ts @@ -19,9 +19,17 @@ import { describe, it } from "@executablemd/test-support/bdd"; import { expect } from "@executablemd/test-support/expect"; -import { createContext, scoped, useScope } from "effection"; +import { createContext, race, scoped, sleep, spawn, useScope, withResolvers } from "effection"; import type { Context, Operation } from "effection"; -import { collect, Component, content, inlineSource, registerComponents } from "../mod.ts"; +import { + collect, + Component, + content, + importComponent, + inlineSource, + registerComponents, +} from "../mod.ts"; +import { importThroughTerminal, MissingImportProvider } from "../src/component-api.ts"; import { executeInstalled } from "../host.ts"; import type { ExecutionInstallation, IdentityClaimant, IdentityComponent } from "../host.ts"; import { getExpansion } from "../src/expansion.ts"; @@ -102,6 +110,30 @@ function probe(seen: Seen, name = "Probe"): IdentityComponent { }; } +/** + * What another loaded copy's empty public terminal raises. + * + * The mark is copied off a genuine report rather than written out here, because + * the mark is exactly the contract between copies: what makes this one foreign is + * its class, which is this file's own. A real second copy is proved to be one of + * these arrangements by `syntax-loaded-copy.test.ts`, which bundles one; what + * matters here is that the class differs while the mark does not. + */ +class ForeignTerminalReport extends Error { + override name = "MissingImportProvider"; +} + +function foreignTerminalReport(asked: string): Error { + const authentic = new MissingImportProvider(asked); + const foreign = new ForeignTerminalReport(authentic.message); + for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(authentic))) { + if (key !== "stack" && key !== "message") { + Object.defineProperty(foreign, key, descriptor); + } + } + return foreign; +} + /** One execution of `source`, with `components` declared to it. */ function run( source: string, @@ -181,21 +213,16 @@ function* seam(): Operation<{ claim: IdentityClaimant; domain: IdentityDomain }> if (claim === undefined || registration === undefined) { throw new Error("the seam produced no claimant"); } - // The seam's own scope, because this seam is not about spawned work: a frame - // belongs to the engine scope that opened it, and this one already runs in a - // scope its caller owns. - const here = yield* useScope(); - const frame = installed.identities.beginImport("Both", here); - installed.identities.select( - "Both", - { - kind: "function", - name: "Both", - props: NO_PROPS, - fn: registration.fn, - }, - here, - ); + // The frame is the only thing a selection can be made into: the engine holds + // it and hands it to the terminal it builds for that import, so this seam + // selects through the frame rather than through the execution. + const frame = installed.identities.beginImport("Both"); + frame.select("Both", { + kind: "function", + name: "Both", + props: NO_PROPS, + fn: registration.fn, + }); const domain = frame.settle(); if (domain === undefined) { throw new Error("canonical selection produced no domain"); @@ -814,6 +841,372 @@ describe("Tier CIV — the identity a host's component names its work after", () * These prove the fact itself: what it reports for each authored form, that * reading it costs nothing, and that it cannot be recovered from anywhere else. */ +describe("Tier CIV — the import's own terminal is the association", () => { + it("CIV26: a handler that delegates through a descendant scope keeps the identity", function* () { + // Ordinary middleware, delegating the same name once — in a scope of its + // own, which the Api allows and which nothing about an import forbids. The + // terminal `next` reaches is the one this import created, so the invocation + // is still in its execution's domain. + const seen = record(); + yield* run("\n", [probe(seen)], function* () { + yield* Component.around( + { + *importComponent([name, position], next) { + return yield* scoped(() => next(name, position)); + }, + }, + { at: "max" }, + ); + }); + + expect(seen.refusals).toEqual([]); + expect(seen.taken).toHaveLength(1); + + // And it is the same identity the undelegated import names, because the + // identity is the authored element's and the delegation changed nothing + // about which element asked. + const direct = record(); + yield* run("\n", [probe(direct)]); + expect(seen.taken).toEqual(direct.taken); + }); + + it("CIV26: nested imports shadow and restore, each through its own terminal", function* () { + // The outer probe expands a body that imports the inner one, so two imports + // are open at once in one scope. Each dispatch owns its terminal, so neither + // needs a stack to find its own frame. + const seen = record(); + yield* run("\n\n\n", [probe(seen, "Outer"), probe(seen, "Probe")]); + + expect(seen.refusals).toEqual([]); + expect(seen.taken).toHaveLength(2); + expect(new Set(seen.taken).size).toBe(2); + }); + + it("CIV26: delegating twice, or delegating another name, names nothing", function* () { + // Each of these reaches this import's terminal — that is not the failure. + // What fails is what the frame then holds: two selections, or one for a + // component the element never wrote. + for (const what of ["twice", "another name"] as const) { + const seen = record(); + yield* run("\n", [probe(seen), probe(seen, "Other")], function* () { + yield* Component.around( + { + *importComponent([name, position], next) { + // Only the element's own import. The root is imported through the + // same operation, and redirecting that is a different mistake. + if (name !== "Probe") { + return yield* next(name, position); + } + if (what === "twice") { + yield* next(name, position); + return yield* next(name, position); + } + return yield* next("Other", position); + }, + }, + { at: "max" }, + ); + }); + + expect([what, seen.taken]).toEqual([what, []]); + expect([what, seen.refusals]).toHaveLength(2); + } + }); + + it("CIV29: a foreign copy's nested import resolves, and is nobody's delegation", function* () { + // A handler starts an import of its own while the authored import is still + // open, through a descriptor carrying the same stable Api name whose terminal + // belongs to another copy of core — what `--include` and a middleware package + // holding its own copy produce. That terminal's "nothing answered this" + // report is not this copy's class, so an execution recognizing it by class + // would propagate the failure instead of resolving the nested import at all. + const foreign = foreignTerminalReport("Other"); + expect(foreign).not.toBeInstanceOf(MissingImportProvider); + + const seen = record(); + const nested: string[] = []; + yield* run("\n", [probe(seen), probe(seen, "Other")], function* () { + yield* Component.around( + { + *importComponent([name, position], next) { + if (name !== "Probe") { + return yield* next(name, position); + } + const answered = yield* importThroughTerminal( + "Other", + position, + // deno-lint-ignore require-yield + function* (asked: string) { + throw foreignTerminalReport(asked); + }, + ); + nested.push(`${answered.kind}:${answered.name}`); + return yield* next(name, position); + }, + }, + { at: "max" }, + ); + }); + + // The nested import was answered by this execution's ordinary resolution, + // with this execution's own implementation of that component. + expect(nested).toEqual(["function:Other"]); + // And the element that was authored is the one holding an identity: a + // separate import is not a delegation of it, however either one resolved. + expect(seen.refusals).toEqual([]); + expect(seen.taken).toHaveLength(1); + const direct = record(); + yield* run("\n", [probe(direct)]); + expect(seen.taken).toEqual(direct.taken); + }); + + it("CIV29: a report naming another import is somebody else's failure", function* () { + // The same arrangement, with the foreign terminal reporting that nothing + // answered a *different* name. Ordinary resolution answers unanswered + // imports, not unrelated failures that happen to carry the mark, so this one + // propagates — and the element that asked says so rather than quietly + // resolving something nobody asked for. + const seen = record(); + let failure = ""; + try { + yield* run("\n", [probe(seen), probe(seen, "Other")], function* () { + yield* Component.around( + { + *importComponent([name, position], next) { + if (name !== "Probe") { + return yield* next(name, position); + } + return yield* importThroughTerminal( + "Other", + position, + // deno-lint-ignore require-yield + function* () { + throw foreignTerminalReport("Elsewhere"); + }, + ); + }, + }, + { at: "max" }, + ); + }); + } catch (error) { + failure = error instanceof Error ? error.message : String(error); + } + + expect(failure).toContain("Elsewhere"); + expect(seen.taken).toEqual([]); + }); +}); + +/** + * How long a signal that a correct engine publishes immediately may go + * unpublished before the wait is called a deadlock. + * + * Never reached by a passing run: every barrier below is opened by the imports + * that arrive at it. An engine that could not hold two imports at once would + * otherwise hang the suite instead of saying what went wrong. + */ +const DEADLOCK_MS = 10_000; + +/** Wait for one signal, reporting a deadlock rather than hanging on one. */ +function* awaiting(what: string, waited: Operation): Operation { + const reached = yield* race([ + (function* (): Operation { + yield* waited; + return true; + })(), + (function* (): Operation { + yield* sleep(DEADLOCK_MS); + return false; + })(), + ]); + if (!reached) { + throw new Error(`${what} never happened: the two imports did not run at the same time`); + } +} + +/** + * Middleware that holds the import of each listed component until every one of + * them is live, and then releases them in `order`. + * + * The rendezvous is inside `importComponent` deliberately. A document holds its + * spawned children at barriers in their component *bodies*, which the import + * has already finished by then — so two such children prove that the bodies + * overlapped, not the imports. Only a wait inside the import itself puts two + * imports in flight together, which is the one arrangement in which an import + * could take a sibling's canonical selection. + * + * A name listed twice holds two separate sites of the same component: each + * arrival takes the next slot that name still has free. + */ +function heldImports(names: readonly string[], order: readonly number[]): () => Operation { + const arrivals = names.map(() => withResolvers()); + const releases = names.map(() => withResolvers()); + const held = names.map(() => false); + return function* () { + yield* spawn(function* () { + for (const [index, name] of names.entries()) { + yield* awaiting(`the import of <${name}> starting`, arrivals[index].operation); + } + for (const index of order) { + releases[index].resolve(); + } + }); + yield* Component.around( + { + *importComponent([name, position], next) { + const index = names.findIndex((listed, at) => listed === name && !held[at]); + if (index < 0) { + return yield* next(name, position); + } + held[index] = true; + arrivals[index].resolve(); + yield* releases[index].operation; + return yield* next(name, position); + }, + }, + { at: "max" }, + ); + }; +} + +describe("Tier CIV — two canonical imports live at the same time", () => { + const CONCURRENT = [ + "", + "", + "", + "", + "", + ].join("\n"); + + const ORDERS: Array<[string, readonly number[]]> = [ + ["in arrival order", [0, 1]], + ["in reverse", [1, 0]], + ]; + + for (const [what, order] of ORDERS) { + it(`CIV27: each of two live imports selects into its own frame, released ${what}`, function* () { + // Both spawned sites are inside their import before either resolves, so + // the frames are open at the same time. Each dispatch reaches the + // terminal it was created with, so neither selection can land in the + // sibling's frame — and which import resolves first decides nothing. + const seen = record(); + yield* run(CONCURRENT, [probe(seen)], heldImports(["Probe", "Probe"], order)); + + expect(seen.refusals).toEqual([]); + expect(seen.taken).toHaveLength(2); + expect(new Set(seen.taken).size).toBe(2); + + // And they are the identities the same two sites name when nothing holds + // their imports at all: overlapping changed the scheduling, not the + // authored element either invocation belongs to. + const direct = record(); + yield* run(CONCURRENT, [probe(direct)]); + expect(new Set(seen.taken)).toEqual(new Set(direct.taken)); + }); + } + + it("CIV28: cancelling one live import closes only its own frame", function* () { + // Three spawned children: one import is released and claims, a second is + // still suspended inside its import when the third fails and `` halts + // it. The cancelled branch settles its own frame in `finally`, and there is + // no execution-wide association for it to take the survivor's with it. + const FIXTURE = [ + "", + "", + "", + "", + "", + "", + ].join("\n"); + + /** A probe that says when it has claimed, so the failure lands after it. */ + function claiming(seen: Seen, done: { resolve(value: void): void }): IdentityComponent { + return { + name: "Probe", + origin: "test://probe", + props: NO_PROPS, + factory: (claim: IdentityClaimant) => + function* Probe( + _props: Record, + invocation: ComponentInvocation, + ): Operation { + try { + seen.taken.push(yield* claim(invocation)); + } catch (error) { + seen.refusals.push(error instanceof Error ? error.message : String(error)); + } + done.resolve(); + return ""; + }, + }; + } + + /** The sibling that decides the run's outcome once the survivor claimed. */ + function tripwire(waited: Operation, outcome: "fails" | "finishes"): IdentityComponent { + return { + name: "Boom", + origin: "test://boom", + props: NO_PROPS, + factory: () => + function* Boom(): Operation { + yield* awaiting("the surviving child claiming", waited); + if (outcome === "fails") { + throw new Error("BOOM"); + } + return ""; + }, + }; + } + + const survived = record(); + const cancelled = record(); + const claimed = withResolvers(); + let failure = ""; + try { + yield* run( + FIXTURE, + [ + claiming(survived, claimed), + probe(cancelled, "Other"), + tripwire(claimed.operation, "fails"), + ], + // `` is listed but never released: its import is live when the + // document fails under it. + heldImports(["Probe", "Other"], [0]), + ); + } catch (error) { + failure = error instanceof Error ? error.message : String(error); + } + + expect(failure).toContain("BOOM"); + // The survivor claimed once and was refused nothing; the branch cancelled + // inside its import claimed nothing at all. + expect(survived.refusals).toEqual([]); + expect(survived.taken).toHaveLength(1); + expect(cancelled.taken).toEqual([]); + + // The same document, with the third child finishing instead of failing: + // both siblings claim, and the survivor names exactly what it named while + // its sibling was being torn down beside it. Nothing outlived that + // teardown to lend or withhold an identity here. + const quiet = record(); + const other = record(); + const finished = withResolvers(); + yield* run( + FIXTURE, + [claiming(quiet, finished), probe(other, "Other"), tripwire(finished.operation, "finishes")], + heldImports(["Probe", "Other"], [0, 1]), + ); + + expect(quiet.refusals).toEqual([]); + expect(other.refusals).toEqual([]); + expect(quiet.taken).toEqual(survived.taken); + expect(other.taken).toHaveLength(1); + expect(new Set([...quiet.taken, ...other.taken]).size).toBe(2); + }); +}); + describe("Tier CIV — the authored form on the invocation", () => { const FORMS: Array<[string, string, boolean]> = [ ["self-closing", "\n", false], @@ -1044,6 +1437,10 @@ describe("Tier CIV — the authored form on the invocation", () => { * invocation in this execution's identity domain is the canonical selection * made inside the frame its own import opened — so these rows are the general * statement of the thing an ordinary `` in each spawn needs. + * + * They take the spawns as the engine schedules them. The rows that hold two + * imports open *together*, by suspending inside the import itself, are CIV27 + * and CIV28 below. */ describe("Tier PA10b — concurrent capability-backed identity", () => { it("PA10b: two concurrent sites each claim their own identity, exactly once", function* () { diff --git a/specs/executable-mdx-spec.md b/specs/executable-mdx-spec.md index 87e4cb61f..6b7327e8c 100644 --- a/specs/executable-mdx-spec.md +++ b/specs/executable-mdx-spec.md @@ -5497,20 +5497,37 @@ the implementation this execution built, carried to the issuance through the engine's own import frame (§5.3), and settled to nothing when resolution did not happen, happened twice, or answered for a name the engine did not ask. -An import frame belongs to the Effection scope that opened it, and each scope -keeps its own innermost-last stack of them. Nesting inside one scope is -unchanged: an inner import owns the top until it closes, after which the outer -one may be selected into again. What the ownership adds is spawned concurrency. -Two `` children under one `` may have imports open at the same time, -and each one's canonical selection is recorded into its own spawn's frame — so an -ordinary `` written in each child receives its own authentic identity, -neither child can be handed the other's, and closing or cancelling one spawn -neither clears nor authorizes the other. Two selections in one frame still -settle to nothing. The engine holds one domain per declared component per -execution however many spawns invoke it, and the same ownership governs the -windows a provider's claim is admitted in: one installation may answer in two -sibling spawns at once, and may answer with the exact same definition in each, -while a second, *different* answer in either refuses. +An import frame belongs to the import that opened it, and the association is +that import's own **terminal**: expansion asks through a `Component` Api +descriptor it creates for this one import, whose core `importComponent` handler +closes over the frame. The descriptor carries the stable `Component` Api name, so +it receives the same installed middleware in the same order — a stable name +shares middleware and shares no terminal authority. Middleware may observe, +delegate, replace or refuse, and may run `next` in a scope of its own: `next` +terminates in the terminal that dispatch was created with, so the invocation +keeps its identity. A handler that calls the public import operation itself is +making a separate import rather than delegating the authored one, and that +separate import grants the authored one no identity. Nothing about an Effection +scope, a context, a token or a durable coroutine takes part. + +What this ownership adds is spawned concurrency. Two `` children under one +`` may have imports open at the same time; each has its own frame behind its +own terminal, so an ordinary `` written in each child receives its own +authentic identity, neither child can be handed the other's, and closing or +cancelling one spawn neither clears nor authorizes the other. Nesting needs no +stack, because an inner authored import is its own dispatch with its own +terminal. Two selections in one frame still settle to nothing. The engine holds +one domain per declared component per execution however many spawns invoke it. + +The windows a provider's claim is admitted in are owned the same way and by the +same kind of value — the explicit window object, captured by the request before +its handler runs — and serially: component answers are resolved in one capture +phase before any document expands, so one window is open at a time and a handler +delegating through a descendant scope answers the resolution it was opened in. +One installation may answer more than one import with the exact same definition, +while a second, *different* answer in either refuses. A concurrent document +import happens after capture, with no window open, so it may be answered as +ordinary middleware and acquires no profile identity. Forwarding the genuine issuance is ordinary delegation and stays supported; everything else refuses. None of it reads replaceable state, so middleware may short-circuit an import, redirect a name, replace a definition, shadow a @@ -13261,6 +13278,9 @@ Defined in §5.6, with the selection rule in §5.3. | CIV23 | The identity a provider states for its answer | A request states a claim on the exact object its handler returns, under the name and provider origin canonical execution fixed when it minted that request. A different object, a copy, an object edited after the claim, a competing provider installation, another key and another revision each identify nothing, and the first statement stands after every one of them. The provider states only key and revision, and a partial identity is refused rather than half-recorded. Backs FE14 | | CIV24 | Identification is one atomic answer | The claim and core's own claim-time copy of what was claimed come back from one call, so nothing downstream reads the chain's object again: an answer whose member alternates between the claimed value and a substitution is sealed as the claimed one, with the plant proven live by the next read. At execution scale, an answer whose props schema alternates validates the fragment against the claimed contract. Backs FE14 | | CIV25 | A request belongs to one resolution occurrence | Provider installation and the right to answer one occurrence are separate. An installation receives a registrar and installs import middleware once; every middleware invocation receives a fresh request with readonly name and position, plus `next`. The request captures the exact resolution-window object, provider-installation token, origin and name, and `claim` accepts only the answer plus key and revision. Its handler closes the request synchronously in `finally` on return, failure or cancellation, while an outer request stays live across `yield* next()` and may claim its replacement after the delegated handler returns. The enclosing resolution closes in its existing `finally`. A claim succeeds only during active execution, through an open request whose captured window is the exact current object and whose fixed name matches it, with no different statement by that provider in the window. Identification takes the expected window explicitly and accepts only that exact window and name. Thus a stale request from resolution N refuses during N+1 of the same name, a stale `Open` request cannot retag while `Other` is live, and a losing inner request refuses after its handler returns while the still-live outer request may claim after delegation. One installation answers several names and repeated same-name resolutions through distinct requests; unidentified replacements remain ordinary valid middleware answers outside fragment evaluation. Two owners live at once each answer only for what they recorded, and tearing one down leaves the other working. No Context, shared symbol, public brand or module-global registry participates. Backs FE15 | +| CIV26 | The terminal is the association | Import middleware that delegates the same name once from inside `scoped()` keeps the invocation's identity, and names the same one an undelegated import does. Two nested authored imports each own their terminal, so both are identified without a stack. Delegating twice, or delegating another name, reaches this import's own terminal and settles it to nothing | +| CIV27 | Two imports live at once | Two `` children are each suspended inside their own import before either resolves. Each dispatch selects into the frame its terminal carries, so both invocations are identified exactly once, their identities differ, and they are the identities the same two sites name when nothing holds their imports — in either release order | +| CIV28 | A cancelled import closes only its own frame | With two imports live, one is released and claims while the other is still suspended and is cancelled by a failing sibling. The survivor is refused nothing and names exactly what that site names when nothing is torn down beside it; the cancelled branch claims nothing, and nothing it left behind lends or withholds an identity afterwards | ### Tier NEX — Nested document executions (`specs/testing-spec.md`) From b5a28acbc0449e07aa10ade7dd5a61378c61c1d5 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 15:49:02 -0400 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=90=9B=20Hand=20one=20import's=20re?= =?UTF-8?q?solution=20to=20expansion,=20not=20to=20the=20boundary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The terminal-owned correlation is unchanged; where the terminal travelled is. `ExecutionEnvironment` is the architecture and product boundary a host's installation and a generated fragment's narrowed table are described against, and an execution-private import resolver does not belong in that interface, whatever it is named and whoever can reach the interface today. So it is gone from it. The resolver is `resolveComponentImport` — "canonical resolution" stays architectural prose for the tier, rather than the name of an operation — and it reaches expansion as an ordinary internal argument beside the environment, typed `ComponentImportTerminal` and declared where it is consumed. Every internal expansion function carries it by hand, so a recursion that dropped it would fail to compile rather than quietly expanding a component body, a branch or a spawned child without its execution's resolution. Execution hands it in at its own root; a direct expansion and a generated fragment are handed none and answer through the ordinary public Component chain, the fragment through the narrowed provider it already installs. Nothing about it is published, keyed, contextual or stored: the only way to have it is to have been given it. The import behavior is the accepted one, unchanged: one authored import owns one terminal and one frame, middleware may delegate `next` through descendant scopes, sibling spawns stay isolated, nested imports each own their terminal, a handler's own direct import is a separate import, another copy's empty terminal is recognized by its mark rather than its class, a mark for another name propagates, and cancelling one import leaves its sibling's identity alone. Two things the boundary rows state, because a boundary is a declaration and not an object: the `ExecutionEnvironment` declaration offers no import terminal — no member accepting an import's frame, whatever it is called — and the type reaches expansion only by hand, published from no entry point and installed in no context or Api. Two corrections from the round before this one are here too. The missing-provider mark is now checked against the complete own-key set, so a payload hiding extras behind a non-enumerable member or a symbol is not the one-member mark it reads as; and three assertions that cast are parsed or declared instead — the runs a child retained are read member by member, a damaged history is built from a declared `DurableEvent`, and a row's two cases come from a declared list. --- architecture.md | 8 +- packages/core/src/component-api.ts | 15 +- packages/core/src/execute.ts | 45 ++-- packages/core/src/execution-environment.ts | 21 -- packages/core/src/expand.ts | 105 ++++++++- packages/core/src/generated-xmd.ts | 4 + .../tests/declared-markdown-component.test.ts | 42 +++- .../core/tests/invocation-identity.test.ts | 201 +++++++++++++++--- 8 files changed, 347 insertions(+), 94 deletions(-) diff --git a/architecture.md b/architecture.md index 2d8678bbd..12e45b4bc 100644 --- a/architecture.md +++ b/architecture.md @@ -136,7 +136,7 @@ and categorization rather than clarify them, so both stay exactly as written. | `JournalProvenance` | a non-operational, equality-only witness that a live publication stream descends from the exact journal backend a provider selected for one workflow run; it grants no append, read, execution, publication or reconciliation capability, and is meaningful only because the provider retains the witness it established and later requires exact equality | | result object | the value a component binds instead of failing: `{ok: true, value}` or `{ok: false, …}`, whose failure members the component declares | | syntax symbols | the complete, versioned description of what a document may write in one directory under one host profile: every structural construct the engine reserves, and the one implementation selection chooses for every other name. It is observation — describing an environment installs no operational state, runs nothing and journals nothing — and it is produced once per request and projected, never rediscovered per format. `xmd syntax` prints one for an environment nobody is running; canonical `` renders one for the site an element was written at, from the same construction and the same Markdown renderer | -| execution environment | the private bundle of services and records one execution supplies while its document expands: what resolves a name, what routes it to a retained implementation, what the execution declared, and the records it keeps about its own identities, forms, vocabulary and source output. The execution builds it from what it captured and admitted, owns it, and passes it by value through canonical expansion — never through a context, because a context resolves by name and a name is not a secret. An expansion driven directly is handed none at all, which is what "nothing is installed here" means; there is no partial one. Its shape is an architecture and product boundary | +| execution environment | the private bundle of services and records one execution supplies while its document expands: what resolves a name, what routes it to a retained implementation, what the execution declared, and the records it keeps about its own identities, forms, vocabulary and source output. The execution builds it from what it captured and admitted, owns it, and passes it by value through canonical expansion — never through a context, because a context resolves by name and a name is not a secret. An expansion driven directly is handed none at all, which is what "nothing is installed here" means; there is no partial one. Its shape is an architecture and product boundary, which is why the resolution an execution performs for one *import* is not on it: that terminal is handed to expansion by hand, as an internal argument beside this bundle, named by no entry point and reachable only by having been given it | | syntax reference | the engine-owned lexical answer to "what may a document write here", carried by value on canonical core's execution environment beside what resolves an import. The execution builds one at its root from the selection inputs it captured before any installation, middleware or document code ran, or from the one set of symbols a trusted host stated for its profile; a trusted canonical evaluation boundary replaces it for the subtree it evaluates. It answers with text and decides nothing: a component the symbols name is not a component anything may run | | run profile declarations | the component registrations a first-party package makes, held as plain values apart from the middleware, providers, activation and launchers its installer also arranges. The installer registers exactly those values and inspection reads exactly those values, so what a run installs and what the symbols report cannot drift | | Plugin | trusted code installed once before an execution imports a root document. XMD bundles exactly one — `@executablemd/git` — and activates it for the run-profile commands: `run`, `plan`, `syntax`, and `workflow start`, `resume` and `fork`. The `xmd test` root is not one of them, because a harness that quietly gained the repository vocabulary would be claiming names its children are entitled to shadow; a nested `` child assembles the profile for itself rather than inheriting what its parent declined. Everything else an operator selects with `--plugin`, and a package that happens to be installed stays inert until it is named. A plain structural value carrying a name and one optional `install`; what it contributes is the existing `ExecutionInstallation` members, and what it composes through are the three stable contextual APIs below. Selecting one runs its module, and selected Plugin code can execute whatever the surrounding runtime permits: it is trusted, and it is not sandboxed | @@ -4026,6 +4026,12 @@ that descriptor, and the selection is recorded by the terminal `next` reaches: - the descriptor carries the same stable Api name as the public one, so it receives the same installed middleware in the same order — **a stable name shares middleware, and shares no terminal authority**; +- the resolution that terminal performs is the execution's own, handed to + expansion as an internal argument beside the execution environment rather than + on it, and carried by every recursion that can invoke a component — so a + component body, a branch and a spawned child resolve the way their execution + does, while an expansion driven directly and a generated fragment are handed + none and answer through the ordinary public chain; - middleware may observe, delegate, replace or refuse the answer, and may run `next` in any descendant scope: `next` still terminates in the terminal that dispatch was created with, so delegating through a scope of its own keeps the diff --git a/packages/core/src/component-api.ts b/packages/core/src/component-api.ts index aeebd1088..f65dd7f95 100644 --- a/packages/core/src/component-api.ts +++ b/packages/core/src/component-api.ts @@ -224,10 +224,12 @@ export class MissingImportProvider extends Error { * import of exactly `asked`. * * The whole mark is parsed rather than trusted: an own, non-enumerable property - * under the namespaced name, holding an object with exactly one member, `asked`, - * whose value is the name this call asked for. Nothing is cast, and a mark that - * names another component — a foreign terminal's report about a *different* - * import, arriving here on some other failure — is not this call's. + * under the namespaced name, holding an object whose complete own-key set is one + * member, `asked`, whose value is the name this call asked for. Nothing is cast; + * a payload carrying anything besides that member, however hidden, is not the + * mark; and a mark that names another component — a foreign terminal's report + * about a *different* import, arriving here on some other failure — is not this + * call's. */ export function isMissingImportProvider(error: unknown, asked: string): boolean { if (typeof error !== "object" || error === null) { @@ -238,7 +240,10 @@ export function isMissingImportProvider(error: unknown, asked: string): boolean return false; } const value: unknown = mark.value; - if (typeof value !== "object" || value === null || Object.keys(value).length !== 1) { + // The complete own-key set, so "one member" means one: `Object.keys()` would + // report a payload carrying hidden extras — a non-enumerable member, a symbol — + // as the single-member mark it is not. + if (typeof value !== "object" || value === null || Reflect.ownKeys(value).length !== 1) { return false; } return Object.getOwnPropertyDescriptor(value, "asked")?.value === asked; diff --git a/packages/core/src/execute.ts b/packages/core/src/execute.ts index 249aada59..f205bdeaa 100644 --- a/packages/core/src/execute.ts +++ b/packages/core/src/execute.ts @@ -83,7 +83,7 @@ import { createBlockCounter, } from "./expand.ts"; import { createReturnBody, missingReturnMessage } from "./return-flow.ts"; -import type { BlockCounter } from "./expand.ts"; +import type { BlockCounter, ComponentImportTerminal } from "./expand.ts"; import { DocumentationError, documentationError, @@ -2022,6 +2022,8 @@ function* runValueRoot( /** This run's record of an unauthorized checked command failure (#441). */ checkedFailures: CheckedFailures, environment: ExecutionEnvironment, + /** This execution's own import resolution, for the expansions below. */ + importTerminal: ComponentImportTerminal, ): Operation { // Created outside the scope the body runs in, so the value it selected is // still readable after that scope — and its teardown — has finished. @@ -2051,6 +2053,7 @@ function* runValueRoot( 0, checkedFailures, environment, + importTerminal, ownBody, ); const exactRecord = environment.sourceSegments; @@ -2076,6 +2079,16 @@ function* runValueRoot( function* documentWorkflow( props: Record, environment: ExecutionEnvironment, + /** + * How this execution resolves one component import, handed to every expansion + * this root causes. + * + * By hand, beside the environment rather than on it: what a host installed and + * what a fragment narrowed are described by the environment, and this is + * neither — it is the execution's own resolution, reachable only by having been + * given it (`expand.ts`). + */ + importTerminal: ComponentImportTerminal, ): Workflow { // This run's memory of a checked command failure it never authorized. Passed // by value into core's own expansion and reachable from nowhere else, so no @@ -2185,6 +2198,7 @@ function* documentWorkflow( rootPath, checkedFailures, environment, + importTerminal, ); } @@ -2208,6 +2222,7 @@ function* documentWorkflow( rootPath, checkedFailures, environment, + importTerminal, undefined, ); // An empty buffered root emits no output event. @@ -2236,6 +2251,7 @@ function* documentWorkflow( 0, checkedFailures, environment, + importTerminal, undefined, ); @@ -2574,17 +2590,20 @@ function* executeDocument( ); /** - * Canonical resolution for one import, and the only thing that puts an - * invocation in one of this execution's identity domains. + * Resolve one component import the way this execution resolves them, and + * the only thing that puts an invocation in one of its identity domains. * - * Held by the execution and handed to expansion by value. Expansion calls - * it as the terminal of a descriptor it created for one authored import, - * passing that import's own frame; the ordinary provider below calls it - * with no frame, for a direct `importComponent()` an invocation started - * itself. Neither path publishes the frame, and nothing outside core can - * name this operation. + * Owned by the execution and handed to expansion **as an argument**, never + * on the environment: `ExecutionEnvironment` is the boundary a host's + * installation and a fragment's narrowed table are described against, and + * an execution-private terminal belongs in neither. Expansion calls this as + * the terminal of a descriptor it created for one authored import, passing + * that import's own frame; the ordinary provider below calls it with no + * frame, for a direct `importComponent()` an invocation started itself. + * Neither path publishes the frame, and nothing outside core can name this + * operation. */ - function* resolveCanonicalImport( + function* resolveComponentImport( name: string, position: Readonly | undefined, selection: ImportSelection | undefined, @@ -2625,8 +2644,6 @@ function* executeDocument( const environment: ExecutionEnvironment = { componentResolution: imports, - // Canonical resolution, for the terminal expansion builds per import. - canonicalImport: resolveCanonicalImport, // Everything this host declared, admitted above. Expansion asks it // about every name it reaches, which is how an installed construct is // dispatched without core holding a branch for its name. @@ -2688,7 +2705,7 @@ function* executeDocument( if (!isMissingImportProvider(error, name)) { throw error; } - return yield* resolveCanonicalImport(name, position, undefined); + return yield* resolveComponentImport(name, position, undefined); } }, *applyModifiers([modifiers, context], _next) { @@ -2725,7 +2742,7 @@ function* executeDocument( const returned = yield* durableRun( function* (): Operation { const issued = issueDocument(props, (claimed) => - documentWorkflow(claimed, environment), + documentWorkflow(claimed, environment, resolveComponentImport), ); try { return yield* beforeAnyImport(issued); diff --git a/packages/core/src/execution-environment.ts b/packages/core/src/execution-environment.ts index cd44999be..189b68944 100644 --- a/packages/core/src/execution-environment.ts +++ b/packages/core/src/execution-environment.ts @@ -30,11 +30,9 @@ import type { ComponentInvocation, ComponentRouting, FormSyntax, - ImportSelection, InvocationIdentities, } from "./invocation-identity.ts"; import type { ExactSource } from "./output/exact-source.ts"; -import type { ComponentDefinition, FunctionComponentDefinition, SourcePosition } from "./types.ts"; import type { SyntaxReference } from "./syntax-reference.ts"; /** @@ -100,25 +98,6 @@ export interface ExecutionEnvironment { * through this. */ readonly componentIdentity?: InvocationIdentities; - /** - * Canonical resolution for one import, as the execution performs it. - * - * Expansion calls this as the terminal of a descriptor it creates for one - * authored import, handing it that import's own frame — so the frame that - * receives the canonical selection is the one the element opened, whatever - * scope a handler delegated through. Absent where nothing canonical resolves - * imports, and then the public chain answers as it always did. - * - * Execution-owned and execution-private: it is on this by-value boundary - * beside component resolution, reaches no document, component or handler, and - * grants nothing by being here — what it decides is what canonical resolution - * decided anyway. - */ - readonly canonicalImport?: ( - name: string, - position: Readonly | undefined, - selection: ImportSelection | undefined, - ) => Operation; /** * Records which segments this execution produced as source rather than prose. * diff --git a/packages/core/src/expand.ts b/packages/core/src/expand.ts index 33d7b24b7..1ba20ed2c 100644 --- a/packages/core/src/expand.ts +++ b/packages/core/src/expand.ts @@ -95,7 +95,7 @@ import { SegmentCauses, useSegmentCauses, } from "./errors.ts"; -import type { InvocationForm } from "./invocation-identity.ts"; +import type { ImportSelection, InvocationForm } from "./invocation-identity.ts"; import { structuralPlacement } from "./execution-declarations.ts"; import type { AdmittedStructural, @@ -172,6 +172,35 @@ export interface BlockCounter { next(): number; } +/** + * How expansion reaches the resolution its execution performs for one import. + * + * Execution owns the resolver and hands it to expansion by hand, as an argument + * beside the environment and never on it: the environment is the architecture + * boundary a host's installation and a fragment's narrowed table are described + * against, and an execution-private terminal belongs in neither. It is not + * exported from a package entry point, installed in no Context or contextual Api, + * and stored in no module-scoped table — the only way to have it is to be handed + * it. + * + * Every internal expansion function carries it beside the environment, so a + * recursion that forgot it would fail to compile rather than quietly expanding a + * component body, a branch or a spawned child without the execution's resolution. + * Two callers legitimately pass none: expansion driven directly, which resolves + * through the ordinary public Component Api, and a generated fragment, whose + * narrowed provider answers its imports and which inherits nothing from the + * document execution that admitted it. + * + * The `selection` is the asking import's own frame (`invocation-identity.ts`). + * Resolution records what it selected there, which is what makes the answer this + * element's rather than whichever import resolved last. + */ +export type ComponentImportTerminal = ( + name: string, + position: Readonly | undefined, + selection: ImportSelection | undefined, +) => Operation; + export function createBlockCounter(): BlockCounter { let id = 0; return { next: () => id++ }; @@ -257,6 +286,7 @@ function expandChildrenScoped( /** Whether the region that caused this expansion grants recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { return scoped(function* () { @@ -280,6 +310,7 @@ function expandChildrenScoped( 0, checkedFailures, environment, + imports, returnBody, ); }); @@ -336,6 +367,7 @@ interface ProjectionState { */ checkedFailures: CheckedFailures | undefined; environment: ExecutionEnvironment | undefined; + imports: ComponentImportTerminal | undefined; } interface ProjectionFrame { @@ -480,6 +512,7 @@ function createProjectionHandle(state: ProjectionState): ProjectionHandle { 0, state.checkedFailures, state.environment, + state.imports, options.returnFrame, ); outcome.resolve({ segments: rendered }); @@ -589,6 +622,7 @@ function createProjectionHandle(state: ProjectionState): ProjectionHandle { 0, state.checkedFailures, state.environment, + state.imports, request.kind === "markdown" ? undefined : state.callerReturn, ); outcome.resolve({ segments: [...errors, ...rendered] }); @@ -794,6 +828,9 @@ export function expandSegments( indexBase, checkedFailures, environment, + // No execution terminal: an expansion driven directly resolves its imports + // through the ordinary public Component Api, exactly as it always has. + undefined, undefined, ); } @@ -873,6 +910,7 @@ function* expandListSegments( */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // An execution opens the table its printed errors record their causes in. @@ -896,6 +934,7 @@ function* expandListSegments( indexBase, checkedFailures, environment, + imports, returnBody, ); }); @@ -1017,6 +1056,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, )), ); @@ -1037,6 +1077,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, )), ); @@ -1058,6 +1099,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, ); break; @@ -1091,6 +1133,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, ); break; @@ -1109,6 +1152,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, ); break; @@ -1130,6 +1174,7 @@ function* expandListSegments( 0, checkedFailures, environment, + imports, returnBody, ); // Which placement this is, answered by identity rather than by name: @@ -1176,6 +1221,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, ); break; @@ -1213,6 +1259,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, ); break; } @@ -1265,6 +1312,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, ); break; @@ -1287,6 +1335,7 @@ function* expandListSegments( elementPath, checkedFailures, environment, + imports, returnBody, ); // A printed error the callee produced is data, and stays data here: it @@ -1431,6 +1480,7 @@ function* expandListSegments( }, checkedFailures, environment, + imports, returnBody, ), ); @@ -1493,6 +1543,7 @@ function* checkedCommandFailure( segment: ErrorSegment, checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // Written down before it is raised or projected, and before the error mode is @@ -1598,6 +1649,7 @@ function* expandLet( /** Whether the enclosing region grants checked-failure recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // Every one of these is decided from what the author wrote, so the whole @@ -1630,6 +1682,7 @@ function* expandLet( 0, checkedFailures, environment, + imports, returnBody, ), ); @@ -1741,6 +1794,7 @@ function* expandEach( /** Whether the region that caused this expansion grants recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // Decided from source alone, so the catalog is shared with validation. A @@ -1800,6 +1854,7 @@ function* expandEach( extendPath(path, { f: "item", i: iteration }), checkedFailures, environment, + imports, returnBody, ); // A `` in the body exits the enclosing ``, so the remaining @@ -1895,6 +1950,7 @@ function* expandIf( /** Whether the enclosing region grants checked-failure recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // Decided from source alone and shared with validation: which props were @@ -1966,6 +2022,7 @@ function* expandIf( 0, checkedFailures, environment, + imports, returnBody, ); } @@ -2035,6 +2092,7 @@ function* expandSwitch( /** Whether the enclosing region grants checked-failure recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // Decided from source alone and shared with validation: which props were @@ -2101,6 +2159,7 @@ function* expandSwitch( 0, checkedFailures, environment, + imports, returnBody, ); } @@ -2176,6 +2235,7 @@ function* expandLoop( /** Whether the enclosing region grants checked-failure recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { const unknownProp = loopPropsViolation(segment); @@ -2233,6 +2293,7 @@ function* expandLoop( 0, checkedFailures, environment, + imports, returnBody, ); if (frame.broken) { @@ -2355,6 +2416,7 @@ function spawnChild( path: string, inherited: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, ): Operation { return scoped(function* () { yield* provideEnv(spawnEnvironment(incoming)); @@ -2383,6 +2445,7 @@ function spawnChild( 0, ledger, environment, + imports, undefined, ); yield* refuseCheckedFailure(ledger); @@ -2427,6 +2490,7 @@ function* expandAll( /** Whether the enclosing region grants checked-failure recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, ): Operation { // Decided from source alone and shared with validation, completely, before a // child is constructed: a malformed `` starts none of them. @@ -2453,6 +2517,7 @@ function* expandAll( path, checkedFailures, environment, + imports, ), ); @@ -2554,6 +2619,7 @@ function* expandPrintErrors( /** The ledger this region grants recovery on top of (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { const refusal = printErrorsViolations(segment)[0]; @@ -2580,6 +2646,7 @@ function* expandPrintErrors( // recovers is not one the run suffered. recoveringLedger(), environment, + imports, returnBody, ); }); @@ -2618,6 +2685,7 @@ function* expandComponent( */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { // Cycle detection — Prosser's algorithm @@ -2677,18 +2745,18 @@ function* expandComponent( // whatever asks first, and authorizes only the answer it produced itself. const offered = environment?.installedComponents?.offer(environment.componentBodyScope, name); let answered: ImportedDefinition; - const canonical = environment?.canonicalImport; try { - // Through this import's own terminal when the execution has one: the - // public middleware chain composes around it by name, and `next` - // terminates in the continuation that carries this frame. Without an - // execution — inspection, a tool describing a document — the ordinary - // public operation answers exactly as it always did. + // Through this import's own terminal when the execution handed expansion + // one: the public middleware chain composes around it by name, and `next` + // terminates in the continuation that carries this frame. Where expansion + // was handed none — driven directly, or a generated fragment answering + // through its own narrowed provider — the ordinary public operation answers + // exactly as it always did. answered = - canonical === undefined + imports === undefined ? yield* importComponent(name, position) : yield* importThroughTerminal(name, position, (asked, at) => - canonical(asked, at, selection), + imports(asked, at, selection), ); } finally { offered?.close(); @@ -2787,6 +2855,7 @@ function* expandComponent( path, checkedFailures, environment, + imports, returnBody, selected, dispatcher, @@ -2933,6 +3002,7 @@ function* expandComponent( printedErrors: bodyContentErrors, checkedFailures, environment, + imports, }); // Published on the eval scope, which every task the invocation owns // descends from — including its persist-eval blocks and its content. @@ -3007,6 +3077,7 @@ function* expandComponent( path, checkedFailures, bodyEnvironment, + imports, returnBody, ); }); @@ -3055,6 +3126,7 @@ function* expandComponent( path, checkedFailures, bodyEnvironment, + imports, returnBody, ); }); @@ -3224,6 +3296,7 @@ function* expandFunctionComponent( /** This work's checked-failure ledger, inherited from the invoking element. */ inherited: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, /** * The identity domain canonical resolution selected for this invocation. @@ -3437,6 +3510,7 @@ function* expandFunctionComponent( ownPath: path, checkedFailures, environment, + imports, }; // Only the ordinary handle is published. The richer projection a // protected body may reach stays a closure at the dispatch below, so @@ -4297,6 +4371,7 @@ export function* expandBody( /** Whether the invoking element sits inside a `` region. */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { if (!bodyHasOutput(bodySegments)) { @@ -4312,6 +4387,7 @@ export function* expandBody( 0, checkedFailures, environment, + imports, returnBody, ); } @@ -4334,6 +4410,7 @@ export function* expandBody( 0, checkedFailures, environment, + imports, returnBody, ); } else if (chunk.output) { @@ -4350,6 +4427,7 @@ export function* expandBody( 0, checkedFailures, environment, + imports, returnBody, ); }); @@ -4368,6 +4446,7 @@ export function* expandBody( chunkBase, checkedFailures, environment, + imports, returnBody, ); }); @@ -4396,6 +4475,7 @@ function runDocumentation( /** Whether the region that caused this expansion grants recovery (§3.6). */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { return scoped(function* () { @@ -4411,6 +4491,7 @@ function runDocumentation( indexBase, checkedFailures, environment, + imports, returnBody, ); }); @@ -4463,6 +4544,7 @@ function* expandValueBody( /** Whether the invoking element sits inside a `` region. */ checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment | undefined, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { const slots = partitionBySlot(children); @@ -4489,6 +4571,7 @@ function* expandValueBody( index, checkedFailures, environment, + imports, ownBody, ); } @@ -4530,6 +4613,7 @@ function* expandInstalledStructural( path: string, checkedFailures: CheckedFailures | undefined, environment: ExecutionEnvironment, + imports: ComponentImportTerminal | undefined, returnBody: ReturnBody | undefined, ): Operation { const name = segment.name; @@ -4631,6 +4715,7 @@ function* expandInstalledStructural( path, checkedFailures, environment, + imports, returnBody, children: segment.children, }); @@ -4683,6 +4768,7 @@ interface RegionContext { readonly path: string; readonly checkedFailures: CheckedFailures | undefined; readonly environment: ExecutionEnvironment; + readonly imports: ComponentImportTerminal | undefined; readonly returnBody: ReturnBody | undefined; readonly children: Segment[]; } @@ -4847,6 +4933,7 @@ function* produceRegion( index, context.checkedFailures, context.environment, + context.imports, context.returnBody, ); } catch (error) { diff --git a/packages/core/src/generated-xmd.ts b/packages/core/src/generated-xmd.ts index 1ad68d9ba..91778dc41 100644 --- a/packages/core/src/generated-xmd.ts +++ b/packages/core/src/generated-xmd.ts @@ -2475,6 +2475,10 @@ function expand( ...(componentRouting === undefined ? {} : { componentRouting }), ...(syntax === undefined ? {} : { syntax }), }, + // No execution terminal: this fragment's imports are answered by the + // narrowed provider installed above, and it inherits nothing of the + // document execution that admitted it. + undefined, // A generated fragment is the engine's own text, so it owns no value body // and a written into it satisfies no declaration. undefined, diff --git a/packages/core/tests/declared-markdown-component.test.ts b/packages/core/tests/declared-markdown-component.test.ts index 454007839..169833a9f 100644 --- a/packages/core/tests/declared-markdown-component.test.ts +++ b/packages/core/tests/declared-markdown-component.test.ts @@ -1435,6 +1435,33 @@ function answeringOpenName(definition: ImportedDefinition): ExecutionInstallatio }; } +/** + * The `{ text, exact }` runs one child's close retained, read rather than + * asserted. + * + * A row about what a durable value *is* cannot cast it into the shape it claims, + * so every member is parsed here and anything else throws — naming what it found — + * instead of arriving at the expectation as a plausible shape nobody checked. + */ +function retainedRuns(event: DurableEvent): { text: string; exact: boolean }[] { + if (event.type !== "close" || event.result.status !== "ok") { + return []; + } + const value = event.result.value; + if (!Array.isArray(value)) { + throw new Error(`the close of ${event.coroutineId} retained no runs: ${JSON.stringify(value)}`); + } + return value.map((entry) => { + if (typeof entry === "object" && entry !== null && !Array.isArray(entry)) { + const { text, exact } = entry; + if (typeof text === "string" && typeof exact === "boolean") { + return { text, exact }; + } + } + throw new Error(`the close of ${event.coroutineId} retained ${JSON.stringify(entry)}`); + }); +} + /** * One replay that is expected to refuse, with whatever it published on the way. * @@ -1646,11 +1673,7 @@ describe("Tier DM — exact source is a provenance, not a field", () => { // What each child retained says what its bytes were, not only what they // said. Read as a set: children close in whatever order they finished, and // which one finished first is exactly what this must not depend on. - const runs = children.flatMap((event) => - event.type === "close" && event.result.status === "ok" && Array.isArray(event.result.value) - ? (event.result.value as { text: string; exact: boolean }[]) - : [], - ); + const runs = children.flatMap((event) => retainedRuns(event)); expect(runs.filter((run) => run.exact)).toEqual([{ text: PRESENTABLE, exact: true }]); expect(runs.some((run) => !run.exact && run.text.includes("ordinary prose"))).toBe(true); @@ -1691,10 +1714,11 @@ describe("Tier DM — exact source is a provenance, not a field", () => { ]; for (const value of damaged) { - const history = complete.map((event) => - event.type === "close" && event.coroutineId.endsWith(".0") - ? { ...event, result: { status: "ok" as const, value } } - : event, + const history = complete.map( + (event): DurableEvent => + event.type === "close" && event.coroutineId.endsWith(".0") + ? { ...event, result: { status: "ok", value } } + : event, ); const attempt = yield* refusalOfRun(source, declarations, history); const which = JSON.stringify(value); diff --git a/packages/core/tests/invocation-identity.test.ts b/packages/core/tests/invocation-identity.test.ts index 88c58d3a9..1d294ef36 100644 --- a/packages/core/tests/invocation-identity.test.ts +++ b/packages/core/tests/invocation-identity.test.ts @@ -134,6 +134,39 @@ function foreignTerminalReport(asked: string): Error { return foreign; } +/** + * The same report, with a payload that reads as one member and is not. + * + * The mark's own key is found structurally rather than written out — the payload + * is the object under it carrying `asked` — so this stays a statement about the + * shape a reader has to parse, not a copy of a constant. The extras are hidden + * exactly the way a reader looking at enumerable string keys alone would miss + * them: one non-enumerable member, one symbol. + */ +function hiddenMemberReport(asked: string): Error { + const authentic = new MissingImportProvider(asked); + const report = new ForeignTerminalReport(authentic.message); + for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(authentic))) { + if (key === "stack" || key === "message") { + continue; + } + const marked: unknown = descriptor.value; + const names = + typeof marked === "object" && marked !== null + ? Object.getOwnPropertyDescriptor(marked, "asked") !== undefined + : false; + if (!names) { + Object.defineProperty(report, key, descriptor); + continue; + } + const payload: Record = { asked }; + Object.defineProperty(payload, "hidden", { value: "not enumerable", enumerable: false }); + Object.defineProperty(payload, Symbol("also hidden"), { value: "not a string key" }); + Object.defineProperty(report, key, { ...descriptor, value: payload }); + } + return report; +} + /** One execution of `source`, with `components` declared to it. */ function run( source: string, @@ -886,7 +919,8 @@ describe("Tier CIV — the import's own terminal is the association", () => { // Each of these reaches this import's terminal — that is not the failure. // What fails is what the frame then holds: two selections, or one for a // component the element never wrote. - for (const what of ["twice", "another name"] as const) { + const ways: readonly ("twice" | "another name")[] = ["twice", "another name"]; + for (const what of ways) { const seen = record(); yield* run("\n", [probe(seen), probe(seen, "Other")], function* () { yield* Component.around( @@ -960,42 +994,66 @@ describe("Tier CIV — the import's own terminal is the association", () => { expect(seen.taken).toEqual(direct.taken); }); - it("CIV29: a report naming another import is somebody else's failure", function* () { - // The same arrangement, with the foreign terminal reporting that nothing - // answered a *different* name. Ordinary resolution answers unanswered - // imports, not unrelated failures that happen to carry the mark, so this one - // propagates — and the element that asked says so rather than quietly - // resolving something nobody asked for. - const seen = record(); - let failure = ""; - try { - yield* run("\n", [probe(seen), probe(seen, "Other")], function* () { - yield* Component.around( - { - *importComponent([name, position], next) { - if (name !== "Probe") { - return yield* next(name, position); - } - return yield* importThroughTerminal( - "Other", - position, - // deno-lint-ignore require-yield - function* () { - throw foreignTerminalReport("Elsewhere"); - }, - ); + /** + * Reports that carry the mark and are still not this call's: one about another + * import, and one whose payload only *looks* like the single member the mark + * is. Each names the fragment its failure has to reach the document with. + */ + const NOT_THIS_CALL: ReadonlyArray<{ + what: string; + report: (asked: string) => Error; + says: string; + }> = [ + { + what: "a report about another import", + report: () => foreignTerminalReport("Elsewhere"), + says: "Elsewhere", + }, + { + what: "a mark carrying hidden members", + report: (asked: string) => hiddenMemberReport(asked), + says: "Other", + }, + ]; + + for (const { what, report, says } of NOT_THIS_CALL) { + it(`CIV29: ${what} is somebody else's failure`, function* () { + // The same arrangement, with the foreign terminal raising something that + // carries the mark without being this call's report of it. Ordinary + // resolution answers imports nothing answered, not unrelated failures, so + // these propagate — and the element that asked says so rather than quietly + // resolving something nobody asked for. + const seen = record(); + let failure = ""; + try { + yield* run("\n", [probe(seen), probe(seen, "Other")], function* () { + yield* Component.around( + { + *importComponent([name, position], next) { + if (name !== "Probe") { + return yield* next(name, position); + } + return yield* importThroughTerminal( + "Other", + position, + // deno-lint-ignore require-yield + function* (asked: string) { + throw report(asked); + }, + ); + }, }, - }, - { at: "max" }, - ); - }); - } catch (error) { - failure = error instanceof Error ? error.message : String(error); - } + { at: "max" }, + ); + }); + } catch (error) { + failure = error instanceof Error ? error.message : String(error); + } - expect(failure).toContain("Elsewhere"); - expect(seen.taken).toEqual([]); - }); + expect([what, failure.includes(says)]).toEqual([what, true]); + expect([what, seen.taken]).toEqual([what, []]); + }); + } }); /** @@ -1070,6 +1128,79 @@ function heldImports(names: readonly string[], order: readonly number[]): () => }; } +/** + * One source file of core's own, read for what it declares. + * + * A boundary is a declaration, so the row about where the execution's import + * resolution may live reads the declarations rather than a runtime object: an + * object says what one execution happened to build, while the interface says what + * every host's installation and every fragment's narrowed table are described + * against. + */ +function sourceOf(file: string): Operation { + return readTextFile(fileURLToPath(new URL(`../${file}`, import.meta.url))); +} + +/** The body of the `ExecutionEnvironment` declaration, as written. */ +function* environmentDeclaration(): Operation { + const source = yield* sourceOf("src/execution-environment.ts"); + const opened = source.indexOf("export interface ExecutionEnvironment {"); + if (opened < 0) { + throw new Error("ExecutionEnvironment is no longer declared where this row reads it"); + } + const closed = source.indexOf("\n}\n", opened); + if (closed < 0) { + throw new Error("the ExecutionEnvironment declaration does not end"); + } + return source.slice(opened, closed); +} + +describe("Tier CIV — where the execution's import resolution lives", () => { + it("CIV30: the environment boundary carries no import terminal", function* () { + const declared = yield* environmentDeclaration(); + // Read as members rather than as text, so this is about what the interface + // offers a holder and not about a word appearing in a comment. + const members = [...declared.matchAll(/^ {2}(?:readonly )?([A-Za-z]+)\??[:(]/gm)].map( + (match) => match[1], + ); + // The row can see the boundary at all: it is the interface with the members + // canonical execution hands expansion, and it still has them. + expect(members).toContain("componentResolution"); + expect(members).toContain("componentIdentity"); + + expect(members).not.toContain("canonicalImport"); + expect(members).not.toContain("resolveComponentImport"); + expect(members).not.toContain("importTerminal"); + // And no member of it accepts an import's own frame or answers with a + // definition, whatever it might be called: that shape *is* an import + // terminal, and naming it something else would not move it off the boundary. + expect(declared).not.toContain("ImportSelection"); + expect(declared).not.toMatch(/=>\s*Operation<\s*\n?\s*ComponentDefinition/); + }); + + it("CIV30: the terminal reaches expansion by hand, and leaves no other way", function* () { + const expansion = yield* sourceOf("src/expand.ts"); + // Declared where it is consumed, and carried as a required parameter beside + // the environment: a recursion that dropped it would not compile, which is + // what the CIV26–CIV29 rows depend on for every nested body, branch and + // spawned child. + expect(expansion).toContain("export type ComponentImportTerminal = ("); + expect(expansion).toContain("imports: ComponentImportTerminal | undefined,"); + // No contextual route to the same value: it is not published under a context + // name and not the core of an Api, so nothing can read it by knowing a name. + expect(expansion).not.toMatch(/createContext<[^>]*ComponentImportTerminal/); + expect(expansion).not.toMatch(/createApi<[^>]*ComponentImportTerminal/); + + // And no package entry point re-exports the type or the identifier, so a + // host, a middleware package and a repository component have no name for it. + for (const entry of ["mod.ts", "api.ts", "host.ts"]) { + const published = yield* sourceOf(entry); + expect([entry, published.includes("ComponentImportTerminal")]).toEqual([entry, false]); + expect([entry, published.includes("resolveComponentImport")]).toEqual([entry, false]); + } + }); +}); + describe("Tier CIV — two canonical imports live at the same time", () => { const CONCURRENT = [ "", From 7141c5ccda3b12da90591b292439d0be792be1e1 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Tue, 29 Sep 2026 18:00:29 -0400 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=93=9D=20Describe=20All=20and=20Spa?= =?UTF-8?q?wn=20for=20authors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/structural.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/core/src/structural.ts b/packages/core/src/structural.ts index 1a295543e..afc5c21fb 100644 --- a/packages/core/src/structural.ts +++ b/packages/core/src/structural.ts @@ -147,10 +147,11 @@ export const STRUCTURAL_DECLARATIONS: readonly EngineStructuralDeclaration[] = [ name: "All", syntax: ["……"], description: - "Run independent work at the same time. " + - "`firstsecond` waits for every spawned child, " + - "then renders their Markdown in authored order even when they finish in another order. " + - "Write at least two `` children directly inside it.", + "Run tasks in parallel. " + + "`firstsecond` expands every task at the same " + + "time, waits for them all to succeed, and preserves their Markdown order. Write at least " + + "two `` children directly inside it; if one fails, unfinished tasks are cancelled " + + "and `` produces no output.", as: null, context: "The `` children this runs at the same time.", }, @@ -158,9 +159,9 @@ export const STRUCTURAL_DECLARATIONS: readonly EngineStructuralDeclaration[] = [ name: "Spawn", syntax: ["…"], description: - "Mark one child for an enclosing `` to run. Write `…` directly " + - "inside ``; bindings made in its content stay in that child, and its `` " + - "or `` cannot target work outside it.", + "Run a task in parallel inside of ``. Write `…` directly inside " + + "``; bindings made in its content stay with that task, and `` or `` " + + "cannot affect work outside it.", as: null, context: "Markdown expanded in its own child, beside its siblings.", },