18 KiB
S1 contextual chain links — contract and isolated probe
Status: proposed contract for root synthesis, not implemented production language or API. The accepted expressivity gap is documented in release-chain-assembly-independent-review-20260906.md. This phase changes harness artifacts only.
Recommended representation
Retain the exact existing RelationBody::SequenceLink { source: Id, target: Id, guard: String } representation and direct-owner meaning. Add one RelationKind::ContextualLink / RelationBody::ContextualLink constructor for caller-owned links with qualified endpoints. Proposed Rust DTOs:
// All structs deny unknown fields. No default missing owner/path/leaf/purpose.
struct OccurrenceEndpoint {
references: Vec<Id>, // ordered SequenceReference occurrence IDs, outermost first
occurrence: Id, // direct leaf contribution in the final resolved sequence
}
enum ContextualLinkPurpose {
Precedence { guard: String },
Exchange { exchange: Id },
CommonWork { work: Id },
}
// Variant of the existing RelationBody, retaining normal relation metadata/ID.
ContextualLink {
owner: Id,
source: OccurrenceEndpoint,
target: OccurrenceEndpoint,
purpose: ContextualLinkPurpose,
}
The source/target accessors required by generic relation consumers can return the leaf occurrence IDs, but must not be used to infer this relation's caller owner. Add a shared contextual_owner / resolved-endpoint accessor and audit every owner/context consumer. An explicit owner avoids guessing whether a leaf's defining chain or the first reference's caller owns the connection. At least one endpoint must have a nonempty reference path for a new Precedence contextual record; ordinary direct precedence remains SequenceLink, so there is one canonical stored spelling for it. Exchange and CommonWork purposes can connect direct or nested Action contributions.
Every path component belongs directly to the current resolved sequence, is a resolved SequenceReference, and targets another same-layer sequence of the same kind. A leaf is a direct contribution in the final sequence. Repeated references to one sequence are distinct instances; equal work IDs or equal leaf IDs do not imply equal addresses. Equality/self checks use (owner, references, occurrence). Reuse cycles reject; ordinary permitted topology cycles remain distinct.
For Precedence, the guard stays opaque authored text and existing appropriate contribution-kind/adjacency rules apply after resolving endpoints. This purpose asserts contextual precedence and creates no engineering exchange. Exchange requires an existing same-layer Interaction (OA) or FunctionalExchange (SA), and both endpoint leaves must be Actions referencing its source and target work. CommonWork requires both endpoint leaves to be Actions referencing the exact same existing work ID. Neither assembly purpose has a guard field: a conditional precedence constraint is a separate typed link, not an invented property of every involvement link. CommonWork does not assert a merged execution or remove either occurrence.
Why exactly these three purposes
The official Creation of Functional Chains and Physical Paths provides the concrete justification:
| Purpose | Primary section and requirement |
|---|---|
| Precedence | Lines 52–64 describe SequenceLinks as contextual ordering with an optional condition. Lines 99–105 explicitly describe folding links whose endpoints are hidden inside referenced chains, including SequenceLinks. |
| Exchange | Lines 79–94 describe assembly through an exchange, using involved functions that need not be chain boundaries. |
| CommonWork | Lines 88–96 describe assembly between two function involvements referencing the same function. |
These are three distinct authored meanings, not three hypothetical future features. The official text does not establish that a common-function link fuses executions, so this contract deliberately leaves that unsupported inference out. Control-node variants, physical paths, scenario gates and runtime scheduling are not added by this proposal.
Concrete JSON, DSL and HTTP shapes
Proposed schema 7 record (owner ends 0001, direct X occurrence 0018, R1 reference 001e, inner B occurrence 0015, engineering exchange 0050):
{
"id": "00000000-0000-4000-8000-000000000090", "alias": "supply_r1_b", "name": "Supply B in first repair",
"description": "Caller-local assembly",
"body": {
"ContextualLink": {
"owner": "00000000-0000-4000-8000-000000000001",
"source": {"references": [], "occurrence": "00000000-0000-4000-8000-000000000018"},
"target": {"references": ["00000000-0000-4000-8000-00000000001e"], "occurrence": "00000000-0000-4000-8000-000000000015"},
"purpose": {"Exchange": {"exchange": "00000000-0000-4000-8000-000000000050"}}
}
}
}
For nested reuse, the target references vector is [R1_REFERENCE_UUID, INNER_REFERENCE_UUID]. For common work, use {"CommonWork":{"work":"B_WORK_UUID"}}. For qualified precedence, use {"Precedence":{"guard":"authorization received"}}. These closed variants make invalid mixtures impossible to accept as ignored fields.
Proposed source declaration, following the existing structured-value syntax:
arcadia 7;
project repair "Repair coordination" {
// Existing declarations are omitted from this illustration.
contextual_link supply_r1_b "Supply B in first repair" id "00000000-0000-4000-8000-000000000090" {
description "Caller-local assembly";
owner @outer;
source { references []; occurrence @x_occurrence; };
target { references [@r1]; occurrence @b_occurrence; };
purpose { Exchange { exchange @x_to_b; }; };
}
}
This is proposed syntax, not a file accepted by the current source-6 parser. Generic structured values should carry it without a second ad hoc path grammar. Reference aliases are resolved by the normal source identity mechanism, including every array member. The caller owns the declaration's source location; editing the contextual link must not move or rewrite the referenced procedure module.
Use the existing POST /api/v1/projects/{id}/transactions with If-Match, body {"commands":[{"CreateRelation": RECORD}],"dry_run":true}; after inspection, submit the same ordinary transaction with dry_run:false and the required current ETag. EditRelation, normal deletion/reidentification, source import/replacement and transition planning use the same core contract. No special assembly endpoint or client-only mutation is required. Actual JSON/OpenAPI fixtures must use literal valid UUIDs and demonstrate valid direct-to-nested and nested-to-nested addresses, wrong path/kind/layer, reversed exchange endpoints, common-work mismatch and stale revision. Preview/refusal must leave source and revision unchanged.
Alternative: extend SequenceLink with default-empty paths
An alternative retains source/target leaf IDs and adds owner plus source_path/target_path and a purpose discriminator to SequenceLink. Empty paths and default Precedence can retain old meaning; serde skip_serializing_if would be needed to retain historical JSON bytes. This is viable only with strict advertised-version admission and a compatibility serializer for old fingerprints.
The alternative loses on the current integration surface: every old SequenceLink destructuring/constructor changes; permissive serde defaults can accidentally admit new properties under old source versions; default purpose/owner reconstruction risks converting omitted fields into guessed semantics; and old model/semantic-review snapshot serialization becomes harder to prove unchanged. Adding paths alone still fails common-work versus exchange assembly, so it is not actually the complete smaller contract. The new constructor keeps all old record shapes exactly unchanged and limits new owner semantics to one clearly identifiable case. It still requires auditing generic source/target consumers; the probe does not pretend otherwise.
Version and checkpoint plan
Use source/interchange 7, even though source 6 is an uncommitted release addition: real source-6 files and private recovery snapshots already exist. Preserve their exact interpretation. Freeze the source-6 constructor set and admit ContextualLink only in 7. Keep all source 1–5 closed admission and migration behavior; neither an explicit empty new path nor the new constructor is admissible there. Never reuse SequenceLink's old guard or endpoint fields to encode a contextual path.
The 6→7 migration changes only the advertised version in the project and the entry's version token. It inserts no model record, ID, link, default path, baseline or review decision; no include/trivia/file bytes change otherwise. Source5→current migration must continue preserving its existing facts and default view-options behavior. Update historical migration tests by checking their actual preserved facts, not simply accepting a new aggregate hash.
Private recovery is a release gate, not post-release cleanup. Current recovery/source5.rs explicitly accepts only a verified (5,6) token-only upgrade and reconstructs historical project/diagram serde order; it cannot silently accept (6,7) or (5,7). Generalize this narrowly with version-specific legacy fingerprint adapters. For 6, preserve the old Project field order and all existing record bytes, using schema_version 6 and refusing any ContextualLink in the historical model shape. For 5, retain the existing omitted Diagram.view_options representation and exact old hash. Verify the complete accepted source bundle differs only at its version token before authorizing a fingerprint rebind. Raw invalid source/property/behavior/workflow buffers must remain exact; only clean baseline buffers may adopt the token change.
Restore no saved executable command or previously accepted plan. Restore the raw typed review decisions under their exact old identity/fingerprint, then replan against the migrated accepted model through the existing recovery mechanism. Preserve explicit approvals only where the current compatibility contract already safely retains them after verified fact-preserving migration; never synthesize new approvals for ContextualLink. Test old source5 and source6 checkpoints with multiline invalid raw drafts, excluded rows and prior explicit decisions, stale fingerprints, forged accepted bytes, unknown new constructors, detached Save As and no original-file overwrite. Changing the global schema constant without these tests would regress an already accepted workflow.
One index, explicit limits, no eager Cartesian expansion
Add one core topology_context module. At each accepted revision build direct owner/contribution/reference/work/exchange indexes once. Resolve only authored or requested addresses with iterative path validation and memoize by full address. Existing direct SequenceLinks adapt to empty-path resolved edges; new links resolve through the same entry point. GUI endpoints, validation, transition closure, source reference/lifecycle handling and semantic review must use this resolver rather than duplicate path walking or owner inference.
Proposed default service/desktop policy for the first bounded implementation: maximum path depth 64; count all path components against the existing 50,000 ordered-reference admission budget, together with ordinary step references; at most 50,000 distinct resolved contextual nodes in an expanded per-owner analysis and 100,000 resolved edges. These are caller resource limits, not new execution semantics, and must be published/tested before freezing. The probe uses smaller configurable limits to falsify enforcement. Structural validation of authored endpoints is linear in their total supplied path length and does not require expanding all combinations of repeated reuse.
Independent review found an error in the first probe's resource model: using current cache length as an address-admission limit makes a valid address fail after unrelated preview activity. The corrected design separates deterministic authored/per-analysis budgets from cache residency. Cache capacity causes eviction or uncached computation, never an invalid-model result. Analysis limits count the current requested unique addresses independently of prior cache contents or traversal order. The revised probe checks both warm-cache orders with capacity one and a separately bounded two-address request; the corrected direct-rustc rerun passed for OA and SA.
Deletion policy proposed for root ratification: normal Delete of an owner, leaf or any reference-path component cascades the whole dependent ContextualLink, preserving its source/history restoration through ordinary Undo. It never trims an address. Retargeting a reference is an edit, so a now-invalid contextual link rejects unless the same explicit batch repairs or deletes that link. Source replacement must supply a coherent final graph; it does not receive an inferred path repair.
Graph projections also need an explicit boundary: precedence/control diagnostics consume SequenceLink plus ContextualLink::Precedence, without turning CommonWork into an execution merge. Exchange/CommonWork assembly incidence is separately available for assembly connectivity and graphical labels. Existing behavior coverage follows actual involvement/reuse identities; it must not turn a caller-only link into an edit of the shared procedure. Caller-qualified warnings carry owner/path/leaf provenance. Root must ratify how assembly-incidence affects any new completeness diagnostics; the resolver probe does not establish those graph-analysis semantics.
Graphical expansion can be paged/lazy and report an explicit visible/total count. It must never claim a truncated graph is complete. If completeness analysis exceeds its bounded expansion, emit a located analysis-limit notice and retain exact structural validity rather than inventing unreachable/entry/exit warnings from a partial graph. The API may reject an explicitly requested oversized expansion; it must not silently return a complete-looking answer. Root should ratify these limits after a repeated-reference scale probe before implementation acceptance.
Isolated probe result and reproducibility
Tracked source: harness/probes/chain_context_resolution.rs. It defines experimental address/purpose/index structs outside oa-core and builds valid OA and SA fixtures using the existing production types. Existing core execution first accepts each complete fixture and rejects the unqualified cross-owner SequenceLink. The experimental resolver then checks r1 versus r2 and two-level nesting, all three purpose constraints, wrong/missing/skipped paths, wrong exchange direction/common work, contextual self-link, retarget/delete refusal, configurable depth/address budgets, cache hits and exact unchanged shared Project.
Direct rustc with warnings denied PASS, both OA and SA. Combined compile/run took about 5.3 seconds. No Cargo/shared target mutation occurred; available host memory before compile was 1,470 MiB. Logs: .local/chain-context-resolution-build.log, .local/chain-context-resolution-run.log; executable .local/chain-context-resolution.exe. The stable linked core artifact was liboa_core-6c8da57367eec642.rlib (last written 19:48:55 local).
That initial pass established address feasibility but retained the subsequently identified cache/admission defect. It is not acceptance of the corrected cache policy. The probe's Precedence branch also does not implement production guard/adjacency validation or the proposed all-direct spelling restriction; those remain explicit core implementation tests, not inferred passes.
Corrective rerun: direct rustc with warnings denied and both OA/SA executions PASS, about 7.2 seconds combined, 1,951 MiB available before compilation. Logs .local/chain-context-resolution-build2.log and .local/chain-context-resolution-run2.log supersede the first run for the cache/analysis-budget assertions. This rerun creates only the ignored executable/logs; no Cargo or shared production/target mutation occurred. The remaining feasibility limits above still apply.
. .local/toolchain/env.ps1
rustc --edition 2024 -D warnings harness/probes/chain_context_resolution.rs `
--crate-name chain_context_resolution `
--extern oa_core=.local/target-gnullvm/debug/deps/liboa_core-6c8da57367eec642.rlib `
-L dependency=.local/target-gnullvm/debug/deps `
-o .local/chain-context-resolution.exe
& .local/chain-context-resolution.exe
Another workspace may have a different hashed rlib filename; use its existing matching core/dependency build. This probe establishes endpoint-resolution feasibility, not production serialization, rendering, full graph analysis, migration/recovery, transition review or HTTP acceptance. Those remain required gates.
Proposed implementation ownership
| Owner | Exclusive files/seams after root grants the implementation phase |
|---|---|
| Core contract worker | New oa-core/src/topology_context.rs and tests; existing model/accessors, validation, references/reidentify/delete, schema7/persistence/source migration, transition closure/mapping and core semantic exact-slot facets. One worker owns existing shared core files. |
| Behavior/UI worker | behavior/topology.rs, topology/{direct,view}.rs, app/process_canvas.rs; qualified hit targets and contextual pickers/inspectors, folding anchors and pending/stale-event tests. Shared app.rs/forms seams only after explicit coordination. |
| Semantic/recovery worker | Existing semantic review adapters and old5/6 checkpoint compatibility plus focused forged/raw-recovery tests; consume core resolver/facets, do not create a parallel endpoint interpretation. |
| Root/integration | Source/API specification, generated OpenAPI/example checks and HTTP fixture tests, package/teaching scope, build leases, native OA/SA repeated+nested reuse/Save/Undo/Redo/reopen gates. |
First implementation checkpoint should be core DTO/resolver/version admission plus executable counterexample/migration tests, before GUI behavior is built on it. Do not commit to the new representation merely because this design probe compiles; root must synthesize the version/purpose/limits decisions and the remaining reviewers may falsify them.