Source-linked AI summary
A Hybrid Dependency-Aware Framework for Task Decomposition and Dynamic Agent Generation in Oracle-to-PostgreSQL Migration
Oleg Grynets, Oleg Kaskun, Alona Seletska, Daryna Tukalo, Vasyl Lyashkevych
TL;DR
Oracle migration involves heterogeneous artifacts whose dependencies and execution order span files, while existing agent workflows often begin with predefined task graphs. The paper derives typed tasks and a dependency graph, then uses task specifications for runtime agent generation. On the reported corpora, selective fallback recovered validated dependencies, and a complementary migration experiment found that some regenerated scripts executed successfully while outcomes varied across object classes.
Problem
The paper asks whether source-derived dependency-aware tasks and dynamic agents can provide a more reliable, efficient, and recoverable migration basis than monolithic or static LLM approaches.
Source: §XVI · p. 16Method
The framework decomposes Oracle artifacts into typed tasks, extracts and validates dependencies with a deterministic-first hybrid process, condenses cycles, and maps task specifications to runtime agents.
Source: §XVI · p. 16, §XVIII · p. 17Results
On 116 Oracle files, fallback recovered 496 additional validated dependencies and removed 165 blind units; across 1,006 PL/SQL files, 380 of 623 regenerated scripts executed successfully.
Source: C. Measured End-to-End Results · p. 12, §XVI · p. 16Takeaways & Limitations
Dependency closures offer a principled way to give each agent the context required by its task and predecessors, while routing can vary by object type.
Source: §XVI · p. 16The 1,006-file experiment did not compare the same tasks under C0–C3, so it cannot establish causal effects of dependency-aware context or dynamic agent generation.
Source: §XVII · p. 17
Abstract
from arXiv · showhide
Large language model (LLM)-based database migration is often treated as direct code transformation, although enterprise Oracle systems contain heterogeneous SQL and PL/SQL artifacts with different dependencies, execution order, complexity, and validation needs. This paper proposes a hybrid dependency-aware framework that identifies migration tasks, builds a cross-file dependency graph, condenses cyclic dependencies, and uses task specifications to generate specialized migration agents at runtime. The deterministic path combines ANTLR-based parsing with typed dependency extraction, while an LLM fallback is invoked only for units that cannot be parsed reliably. On a corpus of 116 Oracle files, the pipeline produced 1,037 units with zero coverage gaps and 1,271 AST-derived dependencies. The fallback processed 165 parse-error units, recovered 496 additional validated dependencies, eliminated unresolved-dependency units, and increased resolved internal edges from 446 to 527. The graph contained four dependency-respecting phases, while cycle handling was validated separately using Tarjan SCC condensation. A complementary experiment on 1,006 PL/SQL files regenerated 623 scripts (~62%), of which 380 (~61%) executed successfully in PostgreSQL 16. Tables achieved about 85% regeneration success, whereas no query regenerations succeeded under the evaluated specification-mediated baseline, and procedural objects remained strongly dependent on schema context. These results motivate dependency-aware context delivery, task-specific validation, and differentiated agent routing. The paper also formalizes task-to-agent mapping, introduces monitoring and diagnostics for execution feedback, and defines a controlled comparison of monolithic, static-decomposition, dependency-aware, and dynamically orchestrated migration strategies.
I. INTRODUCTION
The paper addresses migration of heterogeneous Oracle artifacts whose dependencies and execution semantics span files, proposing source-derived task structure before agent orchestration. It combines deterministic analysis with selective recovery and task-conditioned runtime agents.
A. Background and Motivation
- Oracle artifacts span many object types and implicit execution semantics, while existing agentic decomposition generally assumes an already defined task graph rather than deriving one from legacy source.Longer context windows and prompt compression alone do not recover software dependencies –.Source: A. Background and Motivation · p. 1
- About 85% of tables regenerated successfully, while no query regenerations succeeded under the evaluated specification-mediated baseline and procedural objects often failed with incomplete schema context.The complementary experiment motivates differentiated routing but does not test dependency-aware routing as an ablation.Source: A. Background and Motivation · p. 2
- The framework derives typed migration tasks and cross-file dependencies, then uses task specifications to configure runtime agents with dependency context, risk, and acceptance criteria.Its contributions also include cycle condensation, execution order, parallel phases, and task-to-agent mappings.Source: A. Background and Motivation · pp. 1–2
A. LLM-Assisted Software and Database Migration
- Oracle-to-PostgreSQL migration must preserve cross-object dependencies, execution order, schema assumptions, and traceability across heterogeneous SQL and PL/SQL artifacts [6], [7], [21].Migration pipelines combine source analysis, intermediate representations, retrieval, dependency handling, verification, and target-specific validation.Source: A. LLM-Assisted Software and Database… · p. 2
C. Specification-Driven and Dependency-Aware Execution
- Each decomposed unit can carry an explicit objective, dependencies, constraints, acceptance criteria, and routing hints as the basis for agent creation [26],.This aligns with treating specifications as operational sources of truth rather than passive documentation.Source: C. Specification-Driven and… · p. 2
D. Testing, Monitoring, and Diagnostic Evidence
- Validation spans structural, dependency, execution, and behavioral validity, while monitoring distinguishes local syntax errors from dependency-context or topology errors.Monitoring studies motivate explicit feedback signals, but the proposed routing policy still requires controlled comparison.Source: D. Testing, Monitoring, and Diagnostic… · pp. 2–3
B. Task Decomposition and Agent Orchestration
- Existing agent workflows generally assume a predefined task graph, whereas this framework derives the execution graph from Oracle artifacts for runtime agent generation.The orchestration literature also highlights runtime decomposition, agent generation, scheduling, and dependency-graph-based topology selection [14],,, [20], [24].Source: B. Task Decomposition and Agent… · p. 2, D. Testing, Monitoring, and Diagnostic… · p. 3
III. PROBLEM FORMULATION
The formulation represents each migration unit as an operational task with explicit source, dependency, risk, context, and verification information. Dependencies define a graph that is condensed and layered into work items while keeping decomposition separate from agent-generation policy.
Task representation
- A migration task packages a source fragment, type, dependencies, complexity, risk, required context, and acceptance criteria rather than treating a parsed unit alone as migration-ready.Task specifications connect decomposition to agent generation while leaving runtime orchestration policy separate from deterministic source analysis.Source: §III · pp. 3–4
Dependency graph
- Task dependencies form a directed graph in which referenced defining units must be available before dependent tasks execute or are validated.External objects remain explicit graph nodes or references rather than being discarded.Source: §III · p. 3
Hybrid extraction
- The extraction rule is deterministic-first, using an LLM selectively for parse-error units and validating proposed dependency names against their source fragments.Unsupported dependency candidates are rejected, so the LLM serves as recovery rather than the primary parser.Source: §III · p. 3
Cycle handling and phases
- Strongly connected components are condensed into work items, producing an acyclic graph that can be topologically layered into dependency-respecting phases.Tasks in one phase have no unresolved predecessor relation to one another and can be considered for parallel execution.Source: §III · p. 3
IV. HYBRID DECOMPOSITION AND DEPENDENCY GRAPH CONSTRUCTION
The decomposition pipeline combines grammar-based Oracle parsing with selective LLM recovery, then extracts typed cross-file dependencies and handles cycles before ordering work. Its graph construction preserves source coverage and represents cyclic procedures explicitly rather than imposing an arbitrary internal order.
A. Deterministic Task Identification
- ANTLR supplies structural unit boundaries and typed parsing, while selective LLM slicing is reserved for constructs the grammar cannot parse reliably.Coverage checks assign each source character to an extracted unit or an explicitly handled non-unit region.Source: A. Deterministic Task Identification · p. 4
B. Dependency Extraction and Global Resolution
- A global symbol table maps typed object references to defining units, retains AST or LLM provenance, and records ambiguous matches rather than guessing.Source: B. Dependency Extraction and Global… · p. 4
- Reading statement roles from ANTLR raised dependencies from 1,063 to 1,271 and resolved internal edges from 268 to 446, with zero coverage gaps.CREATE TABLE defines an object, whereas DROP, ALTER, and TRUNCATE reference an existing object and induce ordering dependencies.Source: B. Dependency Extraction and Global… · p. 4
C. Cycle Handling and Parallel Phases
- Tarjan SCC condensation turns mutually dependent procedures into one cycle work item, restoring a DAG for dependency ordering without inventing an internal order.The real corpus had no cycles, so cycle behavior was tested separately on a controlled procedure fixture.Source: C. Cycle Handling and Parallel Phases · pp. 4–5, Figure 2 · p. 5, Figure 3 · p. 5
V. DYNAMIC AGENT GENERATION
The Dynamic Agent Factory converts task metadata into runtime agent configurations, with specialization scaled to task complexity and dependency characteristics. The section also defines an incremental C0–C3 comparison and validation measures for evaluating decomposition and orchestration.
V. DYNAMIC AGENT GENERATION
- Task metadata configures runtime role, model and budget, tools, dependency context, output schema, and validation policy rather than selecting a permanently hard-coded agent.The factory creates task-specific agents that can be discarded after completion, limiting persistent context and communication overhead.Source: §V · p. 5, Figure 4 · p. 5
A. Experimental Configurations
- C0–C3 compare monolithic migration, generic-agent decomposition, dependency-aware decomposition, and hybrid decomposition with dynamic agents to isolate their respective effects.The staged comparison separates decomposition, dependency ordering, and runtime specialization.Source: A. Experimental Configurations · pp. 5–6, Table IV · p. 6
B. Metrics
- Evaluation should cover PostgreSQL syntax and compilation, dependency satisfaction, executable tests, behavioral equivalence where runnable, and operational costs such as latency and retries.The cost-aware effectiveness score is deferred until the quality measurements are available.Source: B. Metrics · p. 6
VII. MEASURED RESULTS OF THE DECOMPOSITION SUBSYSTEM
The 116-file corpus yielded a complete deterministic decomposition, and selective fallback recovered additional validated dependencies from parse-error units. Fallback improved extraction without changing AST-derived dependencies, while cross-file resolution remained an issue.
A. Corpus-Level Deterministic Baseline
- The deterministic run processed 116 files into 1,037 units with zero coverage gaps, 1,271 dependencies, 446 internal edges, 825 external edges, and four phases.It generated 44 DDL-target edges and found no cycles in this corpus.Source: A. Corpus-Level Deterministic Baseline · p. 6
B. Selective LLM Fallback
- The fallback added 496 validated dependencies, eliminated all 165 dependency-blind units, and raised resolved internal edges from 446 to 527, while AST dependencies remained 1,271.The selective fallback processed parse-error units; the AST contribution was unchanged.Source: B. Selective LLM Fallback · p. 6, Table V · p. 6, Figure 5 · p. 7
- Sequential fallback took approximately 37 minutes, compared with graph construction and Tarjan processing on the order of seconds.Source: B. Selective LLM Fallback · p. 6
- After fallback, unresolved-to-internal references increased from 825 to 1,182, so extracting more names did not guarantee successful internal graph resolution.The category includes genuinely external objects as well as references whose internal definitions may remain unresolved.Source: B. Selective LLM Fallback · pp. 6–7
C. Task Complexity Distribution
The extracted tasks span three complexity classes, creating measurable inputs for routing-policy evaluation. The task contract keeps source-derived facts distinct from orchestration choices, while dependency resolution separately represents unresolved, ambiguous, and dynamic references.
C. Task Complexity Distribution
- The 1,037 units comprise 390 low-, 553 medium-, and 94 high-complexity tasks, providing a workload distribution for testing differentiated routing rather than evidence of an optimal topology.Source: C. Task Complexity Distribution · p. 7, Figure 6 · p. 7, Table VI · p. 7
A. From Parsed Unit to Executable Task Contract
- An agent-ready contract links each unit to its source, dependencies and provenance, complexity, objective, acceptance criteria, routing hints, and execution state.Stable identifiers and provenance make outputs traceable to the exact source fragment and graph state; acceptance criteria should be specific enough to validate automatically where possible.Source: A. From Parsed Unit to Executable Task… · pp. 7–8, Table VII · p. 8
- The same task can run under different agent policies because orchestration hints are advisory, not immutable source facts.Routing can change without changing task identity, dependencies, or acceptance criteria.Source: A. From Parsed Unit to Executable Task… · pp. 7–8
B. Dependency Resolution Semantics
- Dependency extraction and resolution are distinct: the resolver retains ambiguous alternatives or external nodes, while dynamic SQL and synonym resolution remain difficult cases.A reference inside EXECUTE IMMEDIATE may not appear as a normal grammar-level dependency; such edges should carry lower confidence or dynamic provenance.Source: B. Dependency Resolution Semantics · p. 8
C. State Model for Agentic Migration
The section defines validation-gated task states and a modular, reproducible pipeline for building dependency graphs. Fixtures test graph and cycle behavior, while low-complexity independent objects illustrate a minimal agent route.
C. State Model for Agentic Migration
- Accepted tasks must satisfy their task-specific evidence requirements; generated artifacts alone are not treated as correct or reliable predecessor context.The state sequence separates generation, static validation, execution, behavioral validation, and acceptance, with failure states attached to transitions.Source: C. State Model for Agentic Migration · p. 8
A. Typed Five-Stage Pipeline
- The five-stage pipeline separates ingestion, parsing, dependency extraction, graph construction, and SCC condensation, with typed handoffs and independently testable stages.Its deterministic path is byte-stable, and the LLM fallback can be enabled in dependency extraction without changing the other stages.Source: A. Typed Five-Stage Pipeline · p. 9
B. Regression and Fixture Strategy
- 565 regression tests passed 564, with one localized DDL-versus-OTHER compatibility regression; a separate fixture validates SCC condensation despite no corpus cycles.The cycle fixture collapses mutually dependent procedures into one SCC work item, followed by dependency-respecting phases.Source: B. Regression and Fixture Strategy · p. 9
A. Low-Complexity Independent Objects
- Low-complexity objects without internal predecessors can use one restricted-tool migration agent and a target-schema validator, avoiding a reviewer when structural criteria pass.The corpus contains 390 such units, making this class available for evaluating cost discipline.Source: A. Low-Complexity Independent Objects · p. 9
B. Dependency-Heavy Procedural Objects
Dependency-heavy procedural objects receive validated predecessor context and execution checks, while cycles, ambiguity, and failures have explicit escalation or containment policies. The section also proposes distinct routing for queries and least-privilege security boundaries.
B. Dependency-Heavy Procedural Objects
- Procedures and functions receive validated predecessor interfaces and artifacts, specialized PL/pgSQL generation, and execution validation; the experiment isolates context and scheduling failures from remaining translation challenges.Oracle exception semantics, packages, autonomous transactions, cursors, and dialect-specific built-ins remain transformation challenges.Source: B. Dependency-Heavy Procedural Objects · p. 9
C. Cycles, Ambiguity, and Human Escalation
- Cycle groups are handled as localized SCC tasks, while unresolved symbol ambiguity preserves candidate definitions and can trigger catalog checks or human confirmation.Human review is risk-based, with high-complexity tasks, unresolved ambiguity, repeated execution failures, security-sensitive transformations, and cycle strategies among possible triggers.Source: C. Cycles, Ambiguity, and Human… · pp. 9–10
D. Alternative Route for Query Tasks
- The baseline's zero successful query regenerations motivate testing direct dialect translation for eligible queries rather than assuming specification-mediated generation fits every task class.Different generation patterns allow evaluation of whether routing selects an appropriate execution strategy, not just a specialized model.Source: D. Alternative Route for Query Tasks · p. 10
A. Failure Containment Across the Dependency Graph
- A failed graph node can be quarantined while independent tasks continue, and validated predecessor artifacts can be reused unless evidence invalidates them.If a predecessor is superseded, the graph identifies descendants that require revalidation; task-linked accepted artifacts also support targeted rollback.Source: A. Failure Containment Across the… · p. 10
B. Security and Tool Boundaries
- Agent tools and credentials should be task-scoped; high-risk actions require a policy gate or human approval, and policy deviations should block execution rather than trigger unrestricted retries.The proposed controls distinguish translation errors from security events and keep secrets outside prompt context.Source: B. Security and Tool Boundaries · p. 10
C. Deployment-Oriented Interpretation of Efficiency
The section frames efficiency as verified progress per cost and distinguishes the specification-first baseline from the proposed dependency-aware extension. It also treats agent termination and tool compliance as separate orchestration outcomes that should be monitored.
C. Deployment-Oriented Interpretation of Efficiency
- Efficiency should be measured as cost per generated, executable, and accepted artifact, because regeneration alone can conceal execution-stage attrition.The supplied baseline regenerated approximately 62% of source files, while about 61% of regenerated scripts passed PostgreSQL execution.Source: C. Deployment-Oriented Interpretation… · pp. 10–11
A. Specification-First Baseline Pipeline
- The baseline strips and decomposes source SQL, then creates a specification and target code per object; the proposed extension adds dependency-aware ordering, cross-file context, and validation-driven recovery.The baseline provides object-level isolation and explicit intermediate specifications, but not cross-file dependency ordering or dependency-scoped context.Source: A. Specification-First Baseline Pipeline · p. 11
B. Agent Loop and Termination Behavior
- The agent loop distinguishes explicit finish, no_tools, and iteration-limit outcomes, separating orchestration failures from SQL translation errors.The loop is capped at ten iterations and averaged approximately three; gpt-oss-120b did not reliably call finish, though this did not change reported migration-performance counts.Source: B. Agent Loop and Termination Behavior · pp. 11–12
C. Measured End-to-End Results
The measured baseline varies substantially by object class, with query regeneration failing and schema mismatch affecting procedural and other objects. The section argues for task-specific validation and task-level observability to diagnose outcomes and compare orchestration configurations.
C. Measured End-to-End Results
- Tables achieved approximately 85% regeneration success, while no query regenerations succeeded; functions, procedures, and indexes most often failed at execution when schema assumptions did not match.The results motivate differentiated routing rather than a single generation policy across object classes.Source: C. Measured End-to-End Results · p. 12, Figure 9 · p. 12
A. Why Execution Testing Must Be Multi-Level
- Migration evaluation distinguishes decomposition, generation, static target, dependency, execution, and behavioral validity, with task-specific acceptance profiles rather than one binary pass/fail.Validation failures are classified before recovery: local syntax errors prompt regeneration, missing predecessors prompt context or scheduling repair, and tool-control failures prompt policy repair.Source: A. Why Execution Testing Must Be… · p. 13, Figure 10 · p. 13
B. Task-Level Observability
- Task-level records link outcomes to graph provenance, agent configuration, tool calls, context size, validation, retries, and cost, enabling comparisons stratified by task characteristics.The monitoring scheme separates local generation repair, dependency repair, and orchestration repair rather than relying only on corpus-wide averages.Source: B. Task-Level Observability · p. 13
C. Diagnostic Categories and Recovery Actions
The framework classifies migration failures so each diagnostic can trigger a targeted recovery action. Task specifications then guide agent configuration and dependency-scoped context delivery.
C. Diagnostic Categories and Recovery Actions
- Seven failure classes distinguish decomposition, dependency extraction and resolution, generation, syntax validation, execution, and semantic or behavioral errors.Each class maps to a different recovery action, from parser extension to human resolution or runtime correction.Source: C. Diagnostic Categories and Recovery… · p. 13
- The orchestrator should choose the narrowest recovery that addresses the diagnosed issue, rather than rerunning the entire pipeline.It can enrich context, postpone a task, or request human resolution depending on whether a dependency is external, unresolved, or scheduled later.Source: C. Diagnostic Categories and Recovery… · pp. 13–14
A. Agent Specification
- Task type, complexity, dependency closure, risk, and acceptance criteria determine an agent’s skill, context, validation strength, and stopping condition.Cycle groups may require coordinated work because they have no valid internal topological order.Source: A. Agent Specification · p. 14
- Routing examples assign simpler tasks to cheaper models and more complex tasks to stronger models or reviewers, but whether specialization offsets token and latency costs remains a hypothesis.The paper does not claim that larger teams are always better.Source: A. Agent Specification · p. 14
B. Dependency-Scoped Context Construction
- Dependency-scoped context supplies validated predecessor outputs or the minimal required subset of a task’s dependency closure, while representing external objects as contracts or schema metadata.This avoids both context starvation and whole-corpus prompting.Source: B. Dependency-Scoped Context… · p. 14
- Context items retain provenance as source code, generated target code, schema metadata, specifications, validation results, or external contracts.The 1,006-file baseline identifies exact schema matching as a frequent execution challenge for functions, procedures, and indexes; dependency-scoped context targets that failure mode but does not guarantee correctness.Source: B. Dependency-Scoped Context… · p. 14
C. Runtime Adaptation and Selective Retry
Runtime adaptation ties retries to validation evidence, while the evaluation plan keeps decomposition evidence separate from migration-level comparisons. It specifies dimensions, metrics, and ablations for testing dependency-aware context and dynamic routing.
C. Runtime Adaptation and Selective Retry
- After validation, passing artifacts become available to successors; failures trigger class-specific recovery such as repair prompts, graph lookup, human disambiguation, model escalation, or verification.Validated predecessors can be reused rather than regenerated after an unrelated local failure.Source: C. Runtime Adaptation and Selective… · p. 14
A. Two Experimental Corpora and Their Roles
- The 116-file corpus evaluates decomposition and dependency recovery, whereas the 1,006-file PL/SQL dataset supplies an execution baseline but does not isolate dependency-aware dynamic-agent effects.A matched, controlled C0–C3 comparison is required for migration-level effects.Source: A. Two Experimental Corpora and Their… · p. 15
B. Evaluation Dimensions and Hypotheses
- Five evaluation dimensions cover decomposition fidelity, fallback recovery, graph validity, migration effectiveness, and orchestration efficiency.The hypotheses separately posit coverage preservation, reduced dependency-blind units, valid SCC-condensed execution structure, increased executable success, and improved quality per cost.Source: B. Evaluation Dimensions and Hypotheses · p. 15
C. Evaluation Metrics and Statistical Reporting
- Executable task success is the primary migration outcome, while regeneration success only records artifact production and does not establish executability.Dependency reporting should distinguish extracted and resolved edges from external, ambiguous, and unresolved dependencies; efficiency measures should separate token, call, latency, and context costs and pair cost with correctness.Source: C. Evaluation Metrics and Statistical… · p. 15
- The C0–C3 ablation progresses from monolithic generation through decomposition and dependency-scoped context to task-conditioned agents and validation-driven recovery.This staged design is intended to attribute observed gains to specific mechanisms rather than simultaneous changes.Source: C. Evaluation Metrics and Statistical… · p. 15
D. Expected Analysis by Object Type
The framework links heterogeneous migration tasks to dependency-aware routing, while experiments show both selective-fallback gains and substantial limits in migration execution evidence. Object-type differences and schema context motivate differentiated strategies, but matched C0–C3 tests remain necessary to establish migration-level effects.
XVI. DISCUSSION
- With AST dependencies fixed at 1,271 in both runs, selective fallback added 496 dependencies and eliminated 165 blind units, isolating the fallback effect from unrelated pipeline changes.Source: §XVI · p. 16
- 1,182 edges remained classified as external versus 527 resolved internal edges, with schema qualification and out-of-corpus objects complicating resolution.Procedures, functions, and indexes also failed when schema prerequisites did not match; this is not causal evidence that graph-conditioned routing will improve them.Source: §XVI · p. 16
- Dependency closures provide a mechanism for progressive disclosure, giving each agent context required by its task and predecessors instead of the entire corpus.This motivation draws on evidence that larger context windows do not guarantee robust use of relevant information.Source: §XVI · p. 16
XVII. THREATS TO VALIDITY
- Dynamic-agent migration gains remain unestablished, and the corpus does not establish natural-cycle frequency or causal benefits of dependency-aware routing.The migration experiment did not compare the same tasks under C0–C3; the 116-file corpus is internal and cannot be redistributed.Source: §XVI · p. 16, §XVII · pp. 16–17
D. Expected Analysis by Object Type
- Object-type and complexity differences motivate routing queries, tables, and complex procedural objects through different migration strategies.The expected analysis also stratifies 390 low-, 553 medium-, and 94 high-complexity units.Source: §XVI · p. 16, D. Expected Analysis by Object Type · p. 16
XVI. DISCUSSION
- 243 of 623 regenerated outputs, approximately 39.0%, did not pass PostgreSQL execution, motivating execution validation within the orchestration loop.Proposed reporting includes first-pass success, success after targeted repair, and marginal token cost per recovered task.Source: §XVI · p. 16
- The proposed provenance trail records specification versions, visible predecessor outputs, models, tools, and validation outcomes for migration artifacts.The framework already records whether dependencies came from AST extraction or LLM recovery.Source: §XVI · p. 16
XVIII. CONCLUSION
- On 1,006 PL/SQL files, 623 were regenerated and 380 regenerated scripts executed successfully in PostgreSQL 16.The conclusion frames executable correctness, semantic quality, token cost, latency, and retry behavior as targets for a matched C0–C3 comparison.Source: §XVIII · p. 17